update path, add python unrar

This commit is contained in:
j 2019-01-29 16:10:06 +05:30
commit 00165d302e
862 changed files with 804 additions and 6 deletions

View file

@ -0,0 +1,156 @@
# __init__.py - main module
# coding: utf-8
#
# Copyright (C) 2010-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
"""Parse, validate and reformat standard numbers and codes.
This library offers functions for parsing, validating and reformatting
standard numbers and codes in various formats.
Currently this package supports the following formats:
* al.nipt: NIPT (Numri i Identifikimit për Personin e Tatueshëm, Albanian VAT number)
* ar.cuit: CUIT (Código Único de Identificación Tributaria, Argentinian tax number)
* at.businessid: Austrian Company Register Numbers
* at.uid: UID (Umsatzsteuer-Identifikationsnummer, Austrian VAT number)
* be.vat: BTW, TVA, NWSt (Belgian VAT number)
* bg.egn: EGN (ЕГН, Единен граждански номер, Bulgarian personal identity codes)
* bg.pnf: PNF (ЛНЧ, Личен номер на чужденец, Bulgarian number of a foreigner)
* bg.vat: VAT (Идентификационен номер по ДДС, Bulgarian VAT number)
* br.cnpj: CNPJ (Cadastro Nacional da Pessoa Jurídica, Brazillian company identifier)
* br.cpf: CPF (Cadastro de Pessoas Físicas, Brazillian national identifier)
* ch.ssn: Swiss social security number ("Sozialversicherungsnummer")
* ch.uid: UID (Unternehmens-Identifikationsnummer, Swiss business identifier)
* ch.vat: VAT, MWST, TVA, IVA, TPV (Mehrwertsteuernummer, the Swiss VAT number)
* cl.rut: RUT (Rol Único Tributario, Chilean national tax number)
* cn.ric: RIC No. (Chinese Resident Identity Card Number)
* co.nit: NIT (Número De Identificación Tributaria, Colombian identity code)
* cusip: CUSIP number (financial security identification number)
* cy.vat: Αριθμός Εγγραφής Φ.Π.Α. (Cypriot VAT number)
* cz.dic: DIČ (Daňové identifikační číslo, Czech VAT number)
* cz.rc: (Rodné číslo, the Czech birth number)
* de.vat: Ust ID Nr. (Umsatzsteur Identifikationnummer, German VAT number)
* de.wkn: Wertpapierkennnummer (German securities identification code)
* dk.cpr: CPR (personnummer, the Danish citizen number)
* dk.cvr: CVR (Momsregistreringsnummer, Danish VAT number)
* do.cedula: Cedula (Dominican Republic national identification number)
* do.rnc: RNC (Registro Nacional del Contribuyente, Dominican Republic tax number)
* ean: EAN (International Article Number)
* ec.ci: CI (Cédula de identidad, Ecuadorian personal identity code)
* ec.ruc: RUC (Registro Único de Contribuyentes, Ecuadorian company tax number)
* ee.ik: Isikukood (Estonian Personcal ID number)
* ee.kmkr: KMKR (Käibemaksukohuslase, Estonian VAT number)
* es.cif: CIF (Certificado de Identificación Fiscal, Spanish company tax number)
* es.dni: DNI (Documento nacional de identidad, Spanish personal identity codes)
* es.nie: NIE (Número de Identificación de Extranjeros, Spanish foreigner number)
* es.nif: NIF (Número de Identificación Fiscal, Spanish VAT number)
* eu.at_02: SEPA Identifier of the Creditor (AT-02)
* eu.vat: VAT (European Union VAT number)
* fi.alv: ALV nro (Arvonlisäveronumero, Finnish VAT number)
* fi.associationid: Finnish Association Identifier
* fi.hetu: HETU (Henkilötunnus, Finnish personal identity code)
* fi.ytunnus: Y-tunnus (Finnish business identifier)
* fr.siren: SIREN (a French company identification number)
* fr.tva: n° TVA (taxe sur la valeur ajoutée, French VAT number)
* gb.sedol: SEDOL number (Stock Exchange Daily Official List number)
* gb.vat: VAT (United Kingdom (and Isle of Man) VAT registration number)
* gr.vat: FPA, ΦΠΑ, ΑΦΜ (Αριθμός Φορολογικού Μητρώου, the Greek VAT number)
* grid: GRid (Global Release Identifier)
* hr.oib: OIB (Osobni identifikacijski broj, Croatian identification number)
* hu.anum: ANUM (Közösségi adószám, Hungarian VAT number)
* iban: IBAN (International Bank Account Number)
* ie.pps: PPS No (Personal Public Service Number, Irish personal number)
* ie.vat: VAT (Irish VAT number)
* imei: IMEI (International Mobile Equipment Identity)
* imo: IMO number (International Maritime Organization number)
* imsi: IMSI (International Mobile Subscriber Identity)
* is_.kennitala: Kennitala (Icelandic personal and organisation identity code)
* is_.vsk: VSK number (Virðisaukaskattsnúmer, Icelandic VAT number)
* isan: ISAN (International Standard Audiovisual Number)
* isbn: ISBN (International Standard Book Number)
* isil: ISIL (International Standard Identifier for Libraries)
* isin: ISIN (International Securities Identification Number)
* ismn: ISMN (International Standard Music Number)
* iso6346: ISO 6346 (International standard for container identification)
* iso9362: ISO 9362 (Business identifier codes)
* issn: ISSN (International Standard Serial Number)
* it.codicefiscale: Codice Fiscale (Italian tax code for individuals)
* it.iva: Partita IVA (Italian VAT number)
* lt.pvm: PVM (Pridėtinės vertės mokestis mokėtojo kodas, Lithuanian VAT number)
* lu.tva: TVA (taxe sur la valeur ajoutée, Luxembourgian VAT number)
* lv.pvn: PVN (Pievienotās vērtības nodokļa, Latvian VAT number)
* meid: MEID (Mobile Equipment Identifier)
* mt.vat: VAT (Maltese VAT number)
* mx.rfc: RFC (Registro Federal de Contribuyentes, Mexican tax number)
* my.nric: NRIC No. (Malaysian National Registration Identity Card Number)
* nl.brin: Brin number (Dutch number for schools)
* nl.bsn: BSN (Burgerservicenummer, Dutch national identification number)
* nl.btw: BTW-nummer (Omzetbelastingnummer, the Dutch VAT number)
* nl.onderwijsnummer: Onderwijsnummer (Dutch student school number)
* nl.postcode: Postcode (Dutch postal code)
* no.mva: MVA (Merverdiavgift, Norwegian VAT number)
* no.orgnr: Orgnr (Organisasjonsnummer, Norwegian organisation number)
* pl.nip: NIP (Numer Identyfikacji Podatkowej, Polish VAT number)
* pl.pesel: PESEL (Polish national identification number)
* pl.regon: REGON (Rejestr Gospodarki Narodowej, Polish register of economic units)
* pt.nif: NIF (Número de identificação fiscal, Portuguese VAT number)
* ro.cf: CF (Cod de înregistrare în scopuri de TVA, Romanian VAT number)
* ro.cnp: CNP (Cod Numeric Personal, Romanian Numerical Personal Code)
* ru.inn: ИНН (Идентификационный номер налогоплательщика, Russian tax identifier)
* se.orgnr: Orgnr (Organisationsnummer, Swedish company number)
* se.vat: VAT (Moms, Mervärdesskatt, Swedish VAT number)
* si.ddv: ID za DDV (Davčna številka, Slovenian VAT number)
* sk.dph: DPH ( pre daň z pridanej hodnoty, Slovak VAT number)
* sk.rc: (Rodné číslo, the Slovak birth number)
* sm.coe: COE (Codice operatore economico, San Marino national tax number)
* us.atin: ATIN (U.S. Adoption Taxpayer Identification Number)
* us.ein: EIN (U.S. Employer Identification Number)
* us.itin: ITIN (U.S. Individual Taxpayer Identification Number)
* us.ptin: PTIN (U.S. Preparer Tax Identification Number)
* us.rtn: RTN (Routing transport number)
* us.ssn: SSN (U.S. Social Security Number)
* us.tin: TIN (U.S. Taxpayer Identification Number)
Furthermore a number of generic check digit algorithms are available:
* iso7064.mod_11_10: The ISO 7064 Mod 11, 10 algorithm
* iso7064.mod_11_2: The ISO 7064 Mod 11, 2 algorithm
* iso7064.mod_37_2: The ISO 7064 Mod 37, 2 algorithm
* iso7064.mod_37_36: The ISO 7064 Mod 37, 36 algorithm
* iso7064.mod_97_10: The ISO 7064 Mod 97, 10 algorithm
* luhn: The Luhn and Luhn mod N algorithms
* verhoeff: The Verhoeff algorithm
All modules implement a common interface:
>>> from stdnum import isbn
>>> isbn.validate('978-9024538270')
'9789024538270'
>>> isbn.validate('978-9024538271')
Traceback (most recent call last):
...
InvalidChecksum: ...
Apart from the validate() function, modules generally provide extra
parsing, validation, formatting or conversion functions.
"""
# the version number of the library
__version__ = '1.2'

View file

@ -0,0 +1,24 @@
# __init__.py - collection of Albanian 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 Albanian numbers."""
# provide vat as an alias
from stdnum.al import nipt as vat

View file

@ -0,0 +1,80 @@
# nipt.py - functions for handling Albanian VAT numbers
# coding: utf-8
#
# Copyright (C) 2008-2011 Cédric Krier
# Copyright (C) 2008-2011 B2CK
# 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
"""NIPT (Numri i Identifikimit për Personin e Tatueshëm, Albanian VAT number).
The Albanian NIPT is a 10-digit number with the first and last character
being letters.
>>> validate('AL J 91402501 L')
'J91402501L'
>>> validate('K22218003V')
'K22218003V'
>>> validate('(AL) J 91402501')
Traceback (most recent call last):
...
InvalidLength: ...
>>> validate('Z 22218003 V')
Traceback (most recent call last):
...
InvalidFormat: ...
"""
import re
from stdnum.exceptions import *
from stdnum.util import clean
# regular expression for matching number
_nipt_re = re.compile(r'^[JKL][0-9]{8}[A-Z]$')
def compact(number):
"""Convert the number to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace."""
number = clean(number, ' ').upper().strip()
if number.startswith('AL'):
number = number[2:]
if number.startswith('(AL)'):
number = number[4:]
return number
def validate(number):
"""Checks to see if the number provided is a valid VAT number. This
checks the length and formatting."""
number = compact(number)
if len(number) != 10:
raise InvalidLength()
if not _nipt_re.match(number):
raise InvalidFormat()
return number
def is_valid(number):
"""Checks to see if the number provided is a valid VAT number. This
checks the length and formatting."""
try:
return bool(validate(number))
except ValidationError:
return False

View file

@ -0,0 +1,24 @@
# __init__.py - collection of Argentinian 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 Argentinian numbers."""
# provide vat as an alias
from stdnum.ar import cuit as vat

View file

@ -0,0 +1,80 @@
# cuit.py - functions for handling Argentinian VAT numbers
# coding: utf-8
#
# Copyright (C) 2009 Mariano Reingart
# Copyright (C) 2011 Sebastián Marró
# Copyright (C) 2008-2011 Cédric Krier
# Copyright (C) 2008-2011 B2CK
# 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
"""CUIT (Código Único de Identificación Tributaria, Argentinian tax number).
The CUIT is a taxpayer identification number used for VAT (IVA, Impuesto al
Valor Agregado) and other taxes.
>>> validate('200-5536168-2')
'20055361682'
>>> validate('2026756539')
Traceback (most recent call last):
...
InvalidLength: ...
>>> validate('2026756A393')
Traceback (most recent call last):
...
InvalidFormat: ...
>>> validate('20267565392')
Traceback (most recent call last):
...
InvalidChecksum: ...
"""
from stdnum.exceptions import *
from stdnum.util import clean
def compact(number):
"""Convert the number to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace."""
return clean(number, ' -').strip()
def calc_check_digit(number):
"""Calculate the check digit."""
weights = (5, 4, 3, 2, 7, 6, 5, 4, 3, 2)
check = sum(w * int(n) for w, n in zip(weights, number)) % 11
return '012345678990'[11 - check]
def validate(number):
"""Checks to see if the number provided is a valid CUIT."""
number = compact(number)
if len(number) != 11:
raise InvalidLength()
if not number.isdigit():
raise InvalidFormat()
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 CUIT."""
try:
return bool(validate(number))
except ValidationError:
return False

View file

@ -0,0 +1,24 @@
# __init__.py - collection of Austrian numbers
# coding: utf-8
#
# Copyright (C) 2012 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 Austrian numbers."""
# provide vat as an alias
from stdnum.at import uid as vat

View file

@ -0,0 +1,70 @@
# businessid.py - functions for handling Austrian company register numbers
#
# Copyright (C) 2015 Holvi Payment Services Oy
# 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
# 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
"""Austrian Company Register Numbers.
The Austrian company register number consist of digits followed by a single
letter, e.g. "122119m". Sometimes it is presented with preceding "FN", e.g.
"FN 122119m".
>>> validate('FN 122119m')
'122119m'
>>> validate('122119m')
'122119m'
>>> validate('m123123')
Traceback (most recent call last):
...
InvalidFormat: ...
>>> validate('abc')
Traceback (most recent call last):
...
InvalidFormat: ...
"""
from stdnum.exceptions import *
from stdnum.util import clean
def compact(number):
"""Convert the number to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace.
Preceding "FN" is also removed."""
number = clean(number, ' -./').strip()
if number.upper().startswith('FN'):
number = number[2:]
return number
def validate(number):
"""Checks to see if the number provided is a valid company register
number. This only checks the formatting."""
number = compact(number)
if not number[-1:].isalpha() or not number[:-1].isdigit():
raise InvalidFormat()
return number
def is_valid(number):
"""Checks to see if the number provided is a valid company register
number. This only checks the formatting."""
try:
return bool(validate(number))
except ValidationError:
return False

View file

@ -0,0 +1,74 @@
# vat.py - functions for handling Austrian VAT numbers
#
# 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
# 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
"""UID (Umsatzsteuer-Identifikationsnummer, Austrian VAT number).
The Austrian UID is a 9-digit number that starts with a U (optionally
preceded with AT). The last digit is a check digit.
>>> validate('AT U13585627')
'U13585627'
>>> calc_check_digit('U1358562')
'7'
>>> validate('U13585626') # incorrect check digit
Traceback (most recent call last):
...
InvalidChecksum: ...
"""
from stdnum import luhn
from stdnum.exceptions import *
from stdnum.util import clean
def compact(number):
"""Convert the number to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace."""
number = clean(number, ' -./').upper().strip()
if number.startswith('AT'):
number = number[2:]
return number
def calc_check_digit(number):
"""Calculate the check digit. The number passed should not have the
check digit included."""
return str((6 - luhn.checksum(number[1:])) % 10)
def validate(number):
"""Checks to see if the number provided is a valid VAT number. This checks
the length, formatting and check digit."""
number = compact(number)
if number[:1] != 'U' or 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 VAT number. This checks
the length, formatting and check digit."""
try:
return bool(validate(number))
except ValidationError:
return False

View file

@ -0,0 +1,21 @@
# __init__.py - collection of Belgian numbers
# coding: utf-8
#
# Copyright (C) 2012 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 Belgian numbers."""

View file

@ -0,0 +1,75 @@
# vat.py - functions for handling Belgian VAT numbers
#
# 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
# 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
"""BTW, TVA, NWSt (Belgian VAT number).
>>> compact('BE403019261')
'0403019261'
>>> compact('(0)403019261')
'0403019261'
>>> validate('BE 428759497')
'0428759497'
>>> validate('BE431150351')
Traceback (most recent call last):
...
InvalidChecksum: ...
"""
from stdnum.exceptions import *
from stdnum.util import clean
def compact(number):
"""Convert the number to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace."""
number = clean(number, ' -./').upper().strip()
if number.startswith('BE'):
number = number[2:]
if number.startswith('(0)'):
number = '0' + number[3:]
if len(number) == 9:
number = '0' + number # old format had 9 digits
return number
def checksum(number):
"""Calculate the checksum."""
return (int(number[:-2]) + int(number[-2:])) % 97
def validate(number):
"""Checks to see if the number provided is a valid VAT number. This checks
the length, formatting and check digit."""
number = compact(number)
if not number.isdigit():
raise InvalidFormat()
if len(number) != 10:
raise InvalidLength()
if checksum(number) != 0:
raise InvalidChecksum()
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

View file

@ -0,0 +1,21 @@
# __init__.py - collection of Bulgarian numbers
# coding: utf-8
#
# Copyright (C) 2012 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 Bulgarian numbers."""

View file

@ -0,0 +1,105 @@
# egn.py - functions for handling Bulgarian national identification numbers
# coding: utf-8
#
# 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
# 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
"""EGN (ЕГН, Единен граждански номер, Bulgarian personal identity codes).
It is a 10-digit number of which the first 6 digits denote the person's
birth date, the next three digits represent a birth order number from
which the person's gender can be determined and the last digit is a check
digit.
>>> compact('752316 926 3')
'7523169263'
>>> validate('8032056031')
'8032056031'
>>> get_birth_date('7542011030')
datetime.date(2075, 2, 1)
>>> validate('7552A10004') # invalid digit
Traceback (most recent call last):
...
InvalidFormat: ...
>>> validate('8019010008') # invalid date
Traceback (most recent call last):
...
InvalidComponent: ...
"""
import datetime
from stdnum.exceptions import *
from stdnum.util import clean
def compact(number):
"""Convert the number to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace."""
return clean(number, ' -.').upper().strip()
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(w * int(n) for w, n in zip(weights, number)) % 11 % 10)
def get_birth_date(number):
"""Split the date parts from the number and return the birth date."""
year = int(number[0:2]) + 1900
month = int(number[2:4])
day = int(number[4:6])
if month > 40:
year += 100
month -= 40
elif month > 20:
year -= 100
month -= 20
try:
return datetime.date(year, month, day)
except ValueError:
raise InvalidComponent()
def validate(number):
"""Checks to see if the number provided is a valid national
identification number. This checks the length, formatting, embedded
date and check digit."""
number = compact(number)
if not number.isdigit():
raise InvalidFormat()
if len(number) != 10:
raise InvalidLength()
# check if birth date is valid
birth_date = get_birth_date(number)
# TODO: check that the birth date is not in the future
# check the check digit
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 national
identification number. This checks the length, formatting, embedded
date and check digit."""
try:
return bool(validate(number))
except ValidationError:
return False

View file

@ -0,0 +1,76 @@
# pnf.py - functions for handling Bulgarian personal number of a foreigner
# coding: utf-8
#
# 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
# 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
"""PNF (ЛНЧ, Личен номер на чужденец, Bulgarian number of a foreigner).
The personal number of a foreigner is a 10-digit number where the last digit
is the result of a weighted checksum.
>>> validate('7111 042 925')
'7111042925'
>>> validate('7111042922') # invalid check digit
Traceback (most recent call last):
...
InvalidChecksum: ...
>>> validate('71110A2922') # invalid digit
Traceback (most recent call last):
...
InvalidFormat: ...
"""
from stdnum.exceptions import *
from stdnum.util import clean
def compact(number):
"""Convert the number to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace."""
return clean(number, ' -.').upper().strip()
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(w * int(n) for w, n in zip(weights, number)) % 10)
def validate(number):
"""Checks to see if the number provided is a valid national
identification number. This checks the length, formatting, embedded
date and check digit."""
number = compact(number)
if not number.isdigit():
raise InvalidFormat()
if len(number) != 10:
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 national
identification number. This checks the length, formatting, embedded
date and check digit."""
try:
return bool(validate(number))
except ValidationError:
return False

View file

@ -0,0 +1,93 @@
# vat.py - functions for handling Bulgarian VAT numbers
# coding: utf-8
#
# 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
# 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
"""VAT (Идентификационен номер по ДДС, Bulgarian VAT number).
The Bulgarian VAT (Данък върху добавената стойност) number is either 9
(for legal entities) or 10 digits (for physical persons, foreigners and
others) long. Each type of number has its own check digit algorithm.
>>> compact('BG 175 074 752')
'175074752'
>>> validate('175074752')
'175074752'
>>> validate('175074751') # invalid check digit
Traceback (most recent call last):
...
InvalidChecksum: ...
"""
from stdnum.bg import egn, pnf
from stdnum.exceptions import *
from stdnum.util import clean
def compact(number):
"""Convert the number to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace."""
number = clean(number, ' -.').upper().strip()
if number.startswith('BG'):
number = number[2:]
return number
def calc_check_digit_legal(number):
"""Calculate the check digit for legal entities. The number passed
should not have the check digit included."""
check = sum((i + 1) * int(n) for i, n in enumerate(number)) % 11
if check == 10:
check = sum((i + 3) * int(n) for i, n in enumerate(number)) % 11
return str(check % 10)
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(w * int(n) for w, n in zip(weights, number))) % 11)
def validate(number):
"""Checks to see if the number provided is a valid VAT number. This
checks the length, formatting and check digit."""
number = compact(number)
if not number.isdigit():
raise InvalidFormat()
if len(number) == 9:
# 9 digit numbers are for legal entities
if number[-1] != calc_check_digit_legal(number[:-1]):
raise InvalidChecksum()
elif len(number) == 10:
# 10 digit numbers are for physical persons, foreigners and others
if not egn.is_valid(number) and not pnf.is_valid(number) and \
number[-1] != calc_check_digit_other(number[:-1]):
raise InvalidChecksum()
else:
raise InvalidLength()
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

View file

@ -0,0 +1,21 @@
# __init__.py - collection of Brazillian numbers
# coding: utf-8
#
# Copyright (C) 2012 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 Brazillian numbers."""

View file

@ -0,0 +1,86 @@
# cnpj.py - functions for handling CNPJ 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
"""CNPJ (Cadastro Nacional da Pessoa Jurídica, Brazillian company identifier).
Numbers from the national register of legal entities have 14 digits. The
first 8 digits identify the company, the following 4 digits identify a
business unit and the last 2 digits are check digits.
>>> validate('16.727.230/0001-97')
'16727230000197'
>>> validate('16.727.230.0001-98')
Traceback (most recent call last):
...
InvalidChecksum: ...
>>> validate('16.727.230/0001=97') # invalid delimiter
Traceback (most recent call last):
...
InvalidFormat: ...
>>> format('16727230000197')
'16.727.230/0001-97'
"""
from stdnum.exceptions import *
from stdnum.util import clean
def compact(number):
"""Convert the number to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace."""
return clean(number, ' -./').strip()
def calc_check_digits(number):
"""Calculate the check digits for the number."""
d1 = (11 - sum(((3 - i) % 8 + 2) * int(n)
for i, n in enumerate(number[:12]))) % 11 % 10
d2 = (11 - sum(((4 - i) % 8 + 2) * int(n)
for i, n in enumerate(number[:12])) -
2 * d1) % 11 % 10
return '%d%d' % (d1, d2)
def validate(number):
"""Checks to see if the number provided is a valid CNPJ. This checks the
length and whether the check digits are correct."""
number = compact(number)
if not number.isdigit() or int(number) <= 0:
raise InvalidFormat()
if len(number) != 14:
raise InvalidLength()
if calc_check_digits(number) != number[-2:]:
raise InvalidChecksum()
return number
def is_valid(number):
"""Checks to see if the number provided is a valid CNPJ. This checks the
length and whether the check digits are correct."""
try:
return bool(validate(number))
except ValidationError:
return False
def format(number):
number = compact(number)
return (number[0:2] + '.' + number[2:5] + '.' + number[5:8] + '/' +
number[8:12] + '-' + number[12:])

View file

@ -0,0 +1,81 @@
# cpf.py - functions for handling CPF numbers
# coding: utf-8
#
# Copyright (C) 2011, 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
# 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
"""CPF (Cadastro de Pessoas Físicas, Brazillian national identifier).
>>> validate('390.533.447-05')
'39053344705'
>>> validate('231.002.999-00')
Traceback (most recent call last):
...
InvalidChecksum: ...
>>> validate('390.533.447=0') # invalid delimiter
Traceback (most recent call last):
...
InvalidFormat: ...
>>> format('23100299900')
'231.002.999-00'
"""
from stdnum.exceptions import *
from stdnum.util import clean
def compact(number):
"""Convert the number to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace."""
return clean(number, ' -.').strip()
def _calc_check_digits(number):
"""Calculate the check digits for the number."""
d1 = sum((10 - i) * int(number[i]) for i in range(9))
d1 = (11 - d1) % 11 % 10
d2 = sum((11 - i) * int(number[i]) for i in range(9)) + 2 * d1
d2 = (11 - d2) % 11 % 10
return '%d%d' % (d1, d2)
def validate(number):
"""Checks to see if the number provided is a valid CPF. This checks
the length and whether the check digit is correct."""
number = compact(number)
if not number.isdigit() or int(number) <= 0:
raise InvalidFormat()
if len(number) != 11:
raise InvalidLength()
if _calc_check_digits(number) != number[-2:]:
raise InvalidChecksum()
return number
def is_valid(number):
"""Checks to see if the number provided is a valid CPF. This checks
the length and whether the check digit is correct."""
try:
return bool(validate(number))
except ValidationError:
return False
def format(number):
"""Reformat the passed number to the standard format."""
number = compact(number)
return number[:3] + '.' + number[3:6] + '.' + number[6:-2] + '-' + number[-2:]

View file

@ -0,0 +1,21 @@
# __init__.py - collection of Swiss numbers
# coding: utf-8
#
# Copyright (C) 2014 Denis Krienbuehl
#
# 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 Swiss numbers."""

View file

@ -0,0 +1,72 @@
# vat.py - functions for handling Swiss social security numbers
#
# Copyright (C) 2014 Denis Krienbuehl
#
# 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
"""Swiss social security number ("Sozialversicherungsnummer").
Also known as "Neue AHV Nummer".
The Swiss Sozialversicherungsnummer is used to identify indivduals for taxation
and pension purposes.
The number is validated using EAN-13, though dashes are substitued for dots.
>>> compact('756.9217.0769.85')
'7569217076985'
>>> format('7569217076985')
'756.9217.0769.85'
>>> validate('7569217076985')
'7569217076985'
>>> validate('756.9217.0769.85')
'7569217076985'
>>> validate('756.9217.0769.84')
Traceback (most recent call last):
...
InvalidChecksum: ...
"""
from stdnum.exceptions import ValidationError
from stdnum import ean
from stdnum.util import clean
def compact(number):
"""Convert the number to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace."""
return clean(number, ' .').strip()
def format(number):
"""Reformat the passed number to the standard format."""
number = compact(number)
return '.'.join((number[:3], number[3:7], number[7:11], number[11:]))
def validate(number):
"""Checks to see if the number provided is a valid
Swiss Sozialversicherungsnummer."""
return ean.validate(compact(number))
def is_valid(number):
"""Checks to see if the number provided is a valid
Sozialversicherungsnummer."""
try:
return bool(validate(number))
except ValidationError:
return False

View file

@ -0,0 +1,90 @@
# uid.py - functions for handling Swiss business identifiers
# 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
"""UID (Unternehmens-Identifikationsnummer, Swiss business identifier).
The Swiss UID is used to uniquely identify businesses for taxation purposes.
The number consists of a fixed "CHE" prefix, followed by 9 digits that are
protected with a simple checksum.
This module only supports the "new" format that was introduced in 2011 which
completely replaced the "old" 6-digit format in 2014.
More information is available at:
https://www.uid.admin.ch/
https://de.wikipedia.org/wiki/Unternehmens-Identifikationsnummer
>>> validate('CHE-100.155.212')
'CHE100155212'
>>> validate('CHE-100.155.213')
Traceback (most recent call last):
...
InvalidChecksum: ...
>>> format('CHE100155212')
'CHE-100.155.212'
"""
from stdnum.exceptions import *
from stdnum.util import clean
def compact(number):
"""Convert the number to the minimal representation. This strips
surrounding whitespace and separators."""
return clean(number, ' -.').strip().upper()
def calc_check_digit(number):
"""Calculate the check digit for organisations. The number passed should
not have the check digit included."""
weights = (5, 4, 3, 2, 7, 6, 5, 4)
s = sum(w * int(n) for w, n in zip(weights, number))
return str((11 - s) % 11)
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) != 12:
raise InvalidLength()
if not number.startswith('CHE'):
raise InvalidComponent()
if not number[3:].isdigit():
raise InvalidFormat()
if number[-1] != calc_check_digit(number[3:-1]):
raise InvalidChecksum()
return number
def is_valid(number):
"""Checks to see if the number provided is a valid number. This checks
the length, formatting and check digit."""
try:
return bool(validate(number))
except ValidationError:
return False
def format(number):
"""Reformat the passed number to the standard format."""
number = compact(number)
return number[:3] + '-' + '.'.join(
number[i:i + 3] for i in range(3, len(number), 3))

View file

@ -0,0 +1,79 @@
# vat.py - functions for handling Swiss VAT 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
"""VAT, MWST, TVA, IVA, TPV (Mehrwertsteuernummer, the Swiss VAT number).
The Swiss VAT number is based on the UID but is followed by either "MWST"
(Mehrwertsteuer, the German abbreviation for VAT), "TVA" (Taxe sur la valeur
ajoutée in French), "IVA" (Imposta sul valore aggiunto in Italian) or "TPV"
(Taglia sin la plivalur in Romanian).
This module only supports the "new" format that was introduced in 2011 which
completely replaced the "old" 6-digit format in 2014.
More information is available at:
https://www.ch.ch/en/value-added-tax-number-und-business-identification-number/
https://www.uid.admin.ch/
>>> validate('CHE-107.787.577 IVA')
'CHE107787577IVA'
>>> validate('CHE-107.787.578 IVA')
Traceback (most recent call last):
...
InvalidChecksum: ...
>>> format('CHE107787577IVA')
'CHE-107.787.577 IVA'
"""
from stdnum.exceptions import *
from stdnum.ch import uid
def compact(number):
"""Convert the number to the minimal representation. This strips
surrounding whitespace and separators."""
return uid.compact(number)
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) not in (15, 16):
raise InvalidLength()
uid.validate(number[:12])
if number[12:] not in ('MWST', 'TVA', 'IVA', 'TPV'):
raise InvalidComponent()
return number
def is_valid(number):
"""Checks to see if the number provided is a valid number. This checks
the length, formatting and check digit."""
try:
return bool(validate(number))
except ValidationError:
return False
def format(number):
"""Reformat the passed number to the standard format."""
number = compact(number)
return uid.format(number[:12]) + ' ' + number[12:]

View file

@ -0,0 +1,25 @@
# __init__.py - collection of Chilean 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 Chilean numbers."""
# provide vat and run as an alias
from stdnum.cl import rut as vat
from stdnum.cl import rut as run

View file

@ -0,0 +1,91 @@
# rut.py - functions for handling Chile RUT/RUN numbers
# coding: utf-8
#
# Copyright (C) 2008-2011 Cédric Krier
# Copyright (C) 2008-2011 B2CK
# 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
"""RUT (Rol Único Tributario, Chilean national tax number).
The RUT, the Chilean national tax number is the same as the RUN (Rol Único
Nacional) the Chilean national identification number. The number consists of
8 digits, followed by a check digit.
>>> validate('76086428-5')
'760864285'
>>> validate('CL 12531909-2')
'125319092'
>>> validate('12531909-3')
Traceback (most recent call last):
...
InvalidChecksum: ...
>>> validate('76086A28-5')
Traceback (most recent call last):
...
InvalidFormat: ...
>>> format('125319092')
'12.531.909-2'
"""
from stdnum.exceptions import *
from stdnum.util import clean
def compact(number):
"""Convert the number to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace."""
number = clean(number, ' -.').upper().strip()
if number.startswith('CL'):
number = number[2:]
return number
def calc_check_digit(number):
"""Calculate the check digit. The number passed should not have the
check digit included."""
s = sum(int(n) * (4 + (5 - i) % 6) for i, n in enumerate(number[::-1]))
return '0123456789K'[s % 11]
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) not in (8, 9):
raise InvalidLength()
if not number[:-1].isdigit():
raise InvalidFormat()
if number[-1] != calc_check_digit(number[:-1]):
raise InvalidChecksum()
return number
def is_valid(number):
"""Checks to see if the number provided is a valid number. This
checks the length, formatting and check digit."""
try:
return bool(validate(number))
except ValidationError:
return False
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])

View file

@ -0,0 +1,21 @@
# __init__.py - collection of United States numbers
# coding: utf-8
#
# Copyright (C) 2014 Jiangge Zhang
#
# 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 China (PRC) numbers."""

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,106 @@
# ric.py - functions for handling Chinese Resident Identity Card Number
#
# Copyright (C) 2014 Jiangge Zhang
#
# 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
"""RIC No. (Chinese Resident Identity Card Number).
The RIC No. is the unique identifier for issued to China (PRC) residents.
The number consist of 18 digits in four sections. The first 6 digits refers to
the resident's location, followed by 8 digits represeting the resident's birth
day in the form YYYY-MM-DD. The next 3 digits is the order code which is the
code used to disambiguate people with the same date of birth and address code.
Men are assigned to odd numbers, women assigned to even numbers. The final
digit is the checksum.
>>> validate('360426199101010071')
'360426199101010071'
"""
import datetime
from stdnum.exceptions import (
ValidationError, InvalidLength, InvalidFormat, InvalidChecksum,
InvalidComponent)
from stdnum.util import clean
def compact(number):
"""Convert the number to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace."""
return clean(number).upper().strip()
def get_birth_date(number):
"""Split the date parts from the number and return the birth date.
Note that in some cases it may return the registration date instead of
the birth date and it may be a century off."""
number = compact(number)
year = int(number[6:10])
month = int(number[10:12])
day = int(number[12:14])
try:
return datetime.date(year, month, day)
except ValueError:
raise InvalidComponent()
def get_birth_place(number):
"""Use the number to look up the place of birth of the person."""
from stdnum import numdb
number = compact(number)
results = numdb.get('cn/loc').info(number[:6])[0][1]
if not results:
raise InvalidComponent()
return results
def calc_check_digit(number):
checksum = (1 - 2 * int(number[:-1], 13)) % 11
return 'X' if checksum == 10 else str(checksum)
def validate(number):
"""Checks to see if the number provided is a valid RIC numbers. This
checks the length, formatting and birth date and place."""
number = compact(number)
if len(number) != 18:
raise InvalidLength()
if not number[:-1].isdigit():
raise InvalidFormat()
if not number[-1].isdigit() and number[-1] != 'X':
raise InvalidFormat()
if number[-1] != calc_check_digit(number):
raise InvalidChecksum()
get_birth_date(number)
get_birth_place(number)
return number
def is_valid(number):
"""Checks to see if the number provided is a valid RIC numbers. This
checks the length, formatting and birth date and place."""
try:
return bool(validate(number))
except ValidationError:
return False
def format(number):
"""Reformat the passed number to the standard format."""
return compact(number)

View file

@ -0,0 +1,25 @@
# __init__.py - collection of Colombian 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 Colombian numbers."""
# provide vat and rut as an alias
from stdnum.co import nit as vat
from stdnum.co import nit as rut

View file

@ -0,0 +1,83 @@
# nit.py - functions for handling Colombian identity codes
# coding: utf-8
#
# Copyright (C) 2008-2011 Cédric Krier
# Copyright (C) 2008-2011 B2CK
# 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
"""NIT (Número De Identificación Tributaria, Colombian identity code).
This number, also referred to as RUT (Registro Unico Tributario) is the
Colombian business tax number.
>>> validate('213.123.432-1')
'2131234321'
>>> validate('2131234325')
Traceback (most recent call last):
...
InvalidChecksum: ...
>>> format('2131234321')
'213.123.432-1'
"""
from stdnum.exceptions import *
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()
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(w * int(n) for w, n in zip(weights, reversed(number))) % 11
return '01987654321'[s]
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 not 8 <= len(number) <= 16:
raise InvalidLength()
if not number.isdigit():
raise InvalidFormat()
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 number. This
checks the length, formatting and check digit."""
try:
return bool(validate(number))
except ValidationError:
return False
def format(number):
"""Reformat the passed number to the standard format."""
number = compact(number)
return '.'.join(
number[i - 3:i] for i in reversed(range(-1, -len(number), -3))
) + '-' + number[-1]

View file

@ -0,0 +1,88 @@
# cusip.py - functions for handling CUSIP numbers
#
# 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
"""CUSIP number (financial security identification number).
CUSIP (Committee on Uniform Securities Identification Procedures) numbers are
used to identify financial securities. CUSIP numbers are a nine-character
alphanumeric code where the first six characters identify the issuer,
followed by two digits that identify and a check digit.
More information:
https://en.wikipedia.org/wiki/CUSIP
https://www.cusip.com/
>>> validate('DUS0421C5')
'DUS0421C5'
>>> validate('DUS0421CN')
Traceback (most recent call last):
...
InvalidChecksum: ...
>>> to_isin('91324PAE2')
'US91324PAE25'
"""
from stdnum.exceptions import *
from stdnum.util import clean
def compact(number):
"""Convert the number to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace."""
return clean(number, ' ').strip().upper()
# O and I are not valid but are accounted for in the check digit calculation
_alphabet = '0123456789ABCDEFGH JKLMN PQRSTUVWXYZ*@#'
def calc_check_digit(number):
"""Calculate the check digits for the number."""
# convert to numeric first, then sum individual digits
number = ''.join(
str((i % 2 + 1) * _alphabet.index(n)) for i, n in enumerate(number))
return str((10 - sum(int(n) for n in number)) % 10)
def validate(number):
"""Checks to see if the number provided is valid. This checks the length
and check digit."""
number = compact(number)
if not all(x in _alphabet for x in number):
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 valid. This checks the length
and check digit."""
try:
return bool(validate(number))
except ValidationError:
return False
def to_isin(number):
"""Convert the number to an ISIN."""
from stdnum import isin
return isin.from_natid('US', number)

View file

@ -0,0 +1,21 @@
# __init__.py - collection of Cypriot numbers
# coding: utf-8
#
# Copyright (C) 2012 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 Cypriot numbers."""

View file

@ -0,0 +1,83 @@
# vat.py - functions for handling Cypriot VAT numbers
# coding: utf-8
#
# 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
# 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
"""Αριθμός Εγγραφής Φ.Π.Α. (Cypriot VAT number).
The Cypriot Αριθμός Εγγραφής Φ.Π.Α. (VAT) number consists of 9 digits
where the last one is a is a letter and functions as a check digit.
>>> compact('CY-10259033P')
'10259033P'
>>> validate('CY-10259033P ')
'10259033P'
>>> validate('CY-10259033Z') # invalid check digit
Traceback (most recent call last):
...
InvalidChecksum: ...
"""
from stdnum.exceptions import *
from stdnum.util import clean
def compact(number):
"""Convert the number to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace."""
number = clean(number, ' -').upper().strip()
if number.startswith('CY'):
number = number[2:]
return number
def calc_check_digit(number):
"""Calculate the check digit. The number passed should not have the
check digit included."""
translation = {
'0': 1, '1': 0, '2': 5, '3': 7, '4': 9,
'5': 13, '6': 15, '7': 17, '8': 19, '9': 21,
}
return 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'[(
sum(translation[x] for x in number[::2]) +
sum(int(x) for x in number[1::2])
) % 26]
def validate(number):
"""Checks to see if the number provided is a valid VAT 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 number[0:2] == '12':
raise InvalidComponent()
if number[-1] != calc_check_digit(number[:-1]):
raise InvalidChecksum()
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

View file

@ -0,0 +1,24 @@
# __init__.py - collection of Czech numbers
# coding: utf-8
#
# Copyright (C) 2012 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 Czech numbers."""
# provide vat as an alias
from stdnum.cz import dic as vat

View file

@ -0,0 +1,101 @@
# dic.py - functions for handling Czech VAT numbers
# coding: utf-8
#
# 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
# 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
"""DIČ (Daňové identifikační číslo, Czech VAT number).
The number is an 8, 9 or 10 digit code that includes a check digit and is
used to uniquely identify taxpayers for VAT (DPH in Czech). The number can
refer to legal entities (8 digit numbers), individuals with a (the 9 or
10 digit Czech birth number) or individuals without a (9 digit numbers
that begin with a 6).
>>> compact('CZ 25123891')
'25123891'
>>> validate('25123891') # legal entity
'25123891'
>>> validate('25123890') # incorrect check digit
Traceback (most recent call last):
...
InvalidChecksum: ...
>>> validate('7103192745') # RČ
'7103192745'
>>> validate('640903926') # special case
'640903926'
"""
from stdnum.cz import rc
from stdnum.exceptions import *
from stdnum.util import clean
def compact(number):
"""Convert the number to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace."""
number = clean(number, ' /').upper().strip()
if number.startswith('CZ'):
number = number[2:]
return number
def calc_check_digit_legal(number):
"""Calculate the check digit for 8 digit legal entities. The number
passed should not have the check digit included."""
check = (11 - sum((8 - i) * int(n) for i, n in enumerate(number))) % 11
return str((check or 1) % 10)
def calc_check_digit_special(number):
"""Calculate the check digit for special cases. The number passed
should not have the first and last digits included."""
check = (11 - sum((8 - i) * int(n) for i, n in enumerate(number))) % 11
return str(9 - check % 10)
def validate(number):
"""Checks to see if the number provided is a valid VAT number. This
checks the length, formatting and check digit."""
number = compact(number)
if not number.isdigit():
raise InvalidFormat()
if len(number) == 8:
# legal entities
if number.startswith('9'):
raise InvalidComponent()
if calc_check_digit_legal(number[:-1]) != number[-1]:
raise InvalidChecksum()
elif len(number) == 9 and number.startswith('6'):
# special cases (skip first digit in calculation)
if calc_check_digit_special(number[1:-1]) != number[-1]:
raise InvalidChecksum()
elif len(number) in (9, 10):
# 9 or 10 digit individual
rc.validate(number)
else:
raise InvalidLength()
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

View file

@ -0,0 +1,117 @@
# rc.py - functions for handling Czech birth numbers
# coding: utf-8
#
# 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
# 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
"""RČ (Rodné číslo, the Czech birth number).
The birth number (, Rodné číslo) is the Czech national identifier. The
number can be 9 or 10 digits long. Numbers given out after January 1st
1954 should have 10 digits. The number includes the birth date of the
person and their gender.
This number is identical to the Slovak counterpart.
>>> validate('710319/2745')
'7103192745'
>>> validate('991231123')
'991231123'
>>> validate('7103192746') # invalid check digit
Traceback (most recent call last):
...
InvalidChecksum: ...
>>> validate('1103492745') # invalid date
Traceback (most recent call last):
...
InvalidComponent: ...
>>> validate('590312/123') # 9 digit number in 1959
Traceback (most recent call last):
...
InvalidLength: ...
>>> format('7103192745')
'710319/2745'
"""
import datetime
from stdnum.exceptions import *
from stdnum.util import clean
def compact(number):
"""Convert the number to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace."""
return clean(number, ' /').upper().strip()
def get_birth_date(number):
"""Split the date parts from the number and return the birth date."""
year = 1900 + int(number[0:2])
# females have 50 added to the month value, 20 is added when the serial
# overflows (since 2004)
month = int(number[2:4]) % 50 % 20
day = int(number[4:6])
# 9 digit numbers were used until January 1st 1954
if len(number) == 9:
if year >= 1980:
year -= 100
if year > 1953:
raise InvalidLength('No 9 digit birth numbers after 1953.')
elif year < 1954:
year += 100
try:
return datetime.date(year, month, day)
except ValueError:
raise InvalidComponent()
def validate(number):
"""Checks to see if the number provided is a valid birth number. This
checks the length, formatting, embedded date and check digit."""
number = compact(number)
if not number.isdigit():
raise InvalidFormat()
if len(number) not in (9, 10):
raise InvalidLength()
# check if birth date is valid
birth_date = get_birth_date(number)
# TODO: check that the birth date is not in the future
# check the check digit (10 digit numbers only)
if len(number) == 10:
check = int(number[:-1]) % 11
# before 1985 the checksum could be 0 or 10
if birth_date < datetime.date(1985, 1, 1):
check = check % 10
if number[-1] != str(check):
raise InvalidChecksum()
return number
def is_valid(number):
"""Checks to see if the number provided is a valid birth number. This
checks the length, formatting, embedded date and check digit."""
try:
return bool(validate(number))
except ValidationError:
return False
def format(number):
"""Reformat the passed number to the standard format."""
number = compact(number)
return number[:6] + '/' + number[6:]

View file

@ -0,0 +1,21 @@
# __init__.py - collection of German numbers
# coding: utf-8
#
# Copyright (C) 2012 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 German numbers."""

View file

@ -0,0 +1,67 @@
# vat.py - functions for handling German VAT numbers
#
# 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
# 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
"""Ust ID Nr. (Umsatzsteur Identifikationnummer, German VAT number).
The number is 10 digits long and uses the ISO 7064 Mod 11, 10 check digit
algorithm.
>>> compact('DE 136,695 976')
'136695976'
>>> validate('DE136695976')
'136695976'
>>> validate('136695978')
Traceback (most recent call last):
...
InvalidChecksum: ...
"""
from stdnum.exceptions import *
from stdnum.iso7064 import mod_11_10
from stdnum.util import clean
def compact(number):
"""Convert the number to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace."""
number = clean(number, ' -./,').upper().strip()
if number.startswith('DE'):
number = number[2:]
return number
def validate(number):
"""Checks to see if the number provided is a valid VAT number. This checks
the length, formatting and check digit."""
number = compact(number)
if not number.isdigit() or number[0] == '0':
raise InvalidFormat()
if len(number) != 9:
raise InvalidLength()
mod_11_10.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

View file

@ -0,0 +1,74 @@
# wkn.py - functions for handling Wertpapierkennnummer
# 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
"""Wertpapierkennnummer (German securities identification code).
The WKN, WPKN, WPK (Wertpapierkennnummer) is a German code to identify
securities. It is a 6-digit alphanumeric number without a check digit that no
longer has any structure. It is expected to be replaced by the ISIN.
>>> validate('A0MNRK')
'A0MNRK'
>>> validate('AOMNRK') # no capital o allowed
Traceback (most recent call last):
...
InvalidFormat: ...
>>> to_isin('SKWM02')
'DE000SKWM021'
"""
from stdnum.exceptions import *
from stdnum.util import clean
def compact(number):
"""Convert the number to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace."""
return clean(number, ' ').strip().upper()
# O and I are not valid but are accounted for in the check digit calculation
_alphabet = '0123456789ABCDEFGH JKLMN PQRSTUVWXYZ'
def validate(number):
"""Checks to see if the number provided is valid. This checks the length
and check digit."""
number = compact(number)
if not all(x in _alphabet for x in number):
raise InvalidFormat()
if len(number) != 6:
raise InvalidLength()
return number
def is_valid(number):
"""Checks to see if the number provided is valid. This checks the length
and check digit."""
try:
return bool(validate(number))
except ValidationError:
return False
def to_isin(number):
"""Convert the number to an ISIN."""
from stdnum import isin
return isin.from_natid('DE', number)

View file

@ -0,0 +1,24 @@
# __init__.py - collection of Danish numbers
# coding: utf-8
#
# Copyright (C) 2012 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 Danish numbers."""
# provide vat as an alias
from stdnum.dk import cvr as vat

View file

@ -0,0 +1,108 @@
# cpr.py - functions for handling Danish CPR numbers
#
# 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
# 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
"""CPR (personnummer, the Danish citizen number).
The CPR is the national number to identify Danish citizens. The number
consists of 10 digits in the format DDMMYY-SSSS where the first part
represents the birth date and the second a sequence number. The first
digit of the sequence number indicates the century.
The numbers used to validate using a checksum but since the sequence
numbers ran out this was abandoned in 2007.
>>> validate('211062-5629')
'2110625629'
>>> checksum('2110625629')
0
>>> validate('511062-5629') # invalid date
Traceback (most recent call last):
...
InvalidComponent: ...
>>> get_birth_date('2110620629')
datetime.date(1962, 10, 21)
>>> get_birth_date('2110525629')
datetime.date(2052, 10, 21)
>>> format('2110625629')
'211062-5629'
"""
import datetime
from stdnum.exceptions import *
from stdnum.util import clean
def compact(number):
"""Convert the number to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace."""
return clean(number, ' -').strip()
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(w * int(n) for w, n in zip(weights, number)) % 11
def get_birth_date(number):
"""Split the date parts from the number and return the birth date."""
day = int(number[0:2])
month = int(number[2:4])
year = int(number[4:6])
if number[6] in '5678' and year >= 58:
year += 1800
elif number[6] in '0123' or (number[6] in '49' and year >= 37):
year += 1900
else:
year += 2000
try:
return datetime.date(year, month, day)
except ValueError:
raise InvalidComponent()
def validate(number):
"""Checks to see if the number provided is a valid CPR number. This
checks the length, formatting, embedded date and check digit."""
number = compact(number)
if not number.isdigit():
raise InvalidFormat()
if len(number) != 10:
raise InvalidLength()
# check if birth date is valid
birth_date = get_birth_date(number)
# TODO: check that the birth date is not in the future
return number
def is_valid(number):
"""Checks to see if the number provided is a valid CPR number. This
checks the length, formatting, embedded date and check digit."""
try:
return bool(validate(number))
except ValidationError:
return False
def format(number):
"""Reformat the passed number to the standard format."""
number = compact(number)
return '-'.join((number[:6], number[6:]))

View file

@ -0,0 +1,71 @@
# cvr.py - functions for handling Danish CVR numbers
#
# 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
# 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
"""CVR (Momsregistreringsnummer, Danish VAT number).
The CVR (Momsregistreringsnummer, VAT) is an 8 digit number with a
straightforward check mechanism.
>>> validate('DK 13585628')
'13585628'
>>> validate('DK 13585627')
Traceback (most recent call last):
...
InvalidChecksum: ...
"""
from stdnum.exceptions import *
from stdnum.util import clean
def compact(number):
"""Convert the number to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace."""
number = clean(number, ' -.,/:').upper().strip()
if number.startswith('DK'):
number = number[2:]
return number
def checksum(number):
"""Calculate the checksum."""
weights = (2, 7, 6, 5, 4, 3, 2, 1)
return sum(w * int(n) for w, n in zip(weights, number)) % 11
def validate(number):
"""Checks to see if the number provided is a valid VAT number. This checks
the length, formatting and check digit."""
number = compact(number)
if not number.isdigit() or number[0] == '0':
raise InvalidFormat()
if len(number) != 8:
raise InvalidLength()
if checksum(number) != 0:
raise InvalidChecksum()
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

View file

@ -0,0 +1,23 @@
# __init__.py - collection of Dominican Republic 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 Dominican Republic numbers."""
from stdnum.do import rnc as vat

View file

@ -0,0 +1,156 @@
# cedula.py - functions for handling Dominican Republic national identifier
#
# 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
"""Cedula (Dominican Republic national identification number).
A cedula is is an 11-digit number issues by the Dominican Republic government
to citizens or residents for identification purposes.
>>> validate('00113918205')
'00113918205'
>>> validate('00113918204')
Traceback (most recent call last):
...
InvalidChecksum: ...
>>> validate('0011391820A')
Traceback (most recent call last):
...
InvalidFormat: ...
>>> format('22400022111')
'224-0002211-1'
"""
from stdnum.exceptions import *
from stdnum.util import clean
from stdnum import luhn
# list of Cedulas that do not match the checksum but are nonetheless valid
whitelist = set('''
00000021249 00000035692 00000058035 00000065377 00000078587 00000111941
00000126295 00000140874 00000155482 00000236621 00000292212 00000564933
00000719400 00004110056 00100000169 00100012146 00100013114 00100016495
00100053841 00100061611 00100061945 00100083860 00100101767 00100126468
00100145737 00100165504 00100169706 00100172940 00100174666 00100181057
00100228718 00100231017 00100238382 00100239662 00100255349 00100288143
00100288929 00100322649 00100350928 00100378440 00100384523 00100415853
00100523399 00100524531 00100530588 00100587320 00100590683 00100593378
00100622461 00100709215 00100728113 00100729795 00100756082 00100759932
00101118022 00101166065 00101527366 00101541404 00101621981 00101659661
00101684656 00101686299 00101821735 00101961125 00102025201 00102398239
00102577448 00102630192 00103266558 00103436936 00103443802 00103754365
00103822440 00103983004 00104486903 00104532086 00104662561 00104727362
00104785104 00104862525 00105263314 00105328185 00105512386 00105530894
00105606543 00105832408 00106190966 00106284933 00106418989 00106442522
00106479922 00106916538 00107045499 00107184305 00107445493 00107602067
00107665688 00107687383 00107691942 00108113363 00108132448 00108184024
00108264871 00108286792 00108384121 00108413431 00108497822 00108784684
00108796883 00109183462 00109229090 00109402756 00109785951 00109987435
00110047715 00110071113 00110111536 00110490843 00110578459 00110646203
00111014782 00111150559 00113453700 00114272360 00114532330 00114532355
00114687216 00115039795 00115343847 00116256005 00116448241 00116508511
00117582001 00119161853 00121344165 00121581750 00121581800 00129737056
00130610001 00131257003 00133987848 00134588056 00142864013 00143072001
00144435001 00146965001 00147485003 00149657590 00155144906 00161884001
00162906003 00163540003 00163549012 00163709018 00166533003 00167311001
00170009162 00170115579 00171404771 00174729003 00174940001 00181880003
00184129003 00189213001 00189405093 00190002567 00196714003 00200021994
00200028716 00200040516 00200063601 00200123640 00200291381 00200409772
00200435544 00200969260 00201023001 00202110760 00202744522 00207327056
00208430205 00208832003 00218507031 00222017001 00235482001 00236245013
00241997013 00246160013 00261011013 00270764013 00274652001 00278005023
00289931003 00291431001 00291549003 00297018001 00298109001 00299724003
00300001538 00300011700 00300013835 00300017875 00300019575 00300020806
00300025568 00300052890 00300169535 00300244009 00300636564 00301200901
00305535206 00345425001 00352861001 00356533003 00362684023 00376023023
00400001552 00400001614 00400012957 00400189811 00425759001 00435518003
00475916056 00481106001 00481595003 00493593003 00516077003 00520207699
00524571001 00539342005 00540077717 00544657001 00574599001 00599408003
00633126023 00644236001 00648496171 00651322001 00686904003 00720758056
00731054054 00741721056 00757398001 00800106971 00848583056 00857630012
00971815056 01000005580 01000250733 01000268998 01000728704 01000855890
01038813907 01094560111 01100014261 01100620962 01154421047 01200004166
01200008613 01200011252 01200014133 01200033420 01200771767 01300001142
01300005424 01300020331 01400000282 01400074875 01600009531 01600019983
01600026316 01600027894 01650257001 01700052445 01700200811 01800022457
01800058439 01800527104 01810035037 02038569001 02100061022 02300003061
02300023225 02300031758 02300037618 02300047220 02300052220 02300054193
02300062066 02300085158 02400229955 02500045676 02600036132 02600094954
02700029905 02755972001 02800000129 02800021761 02800025877 02800029588
02831146001 03000411295 03100109611 03100488033 03100654224 03100673050
03100963776 03101070888 03102828522 03102936385 03103315310 03103749672
03104354892 03111670001 03121982479 03200066940 03300023841 03400058730
03400157849 03401709701 03500037890 03600046116 03600127038 03600180637
03700663589 03800032522 03807240010 03852380001 03900069856 03900192284
04022130495 04400002002 04600198229 04700004024 04700020933 04700027064
04700061076 04700070460 04700074827 04700221469 04701174268 04800019561
04800034846 04800046910 04800956889 04801245892 04900009932 04900011690
04900013913 04900014592 04900026260 04900028443 04900448230 04902549001
04941042001 05100085656 05300013029 05400016031 05400021759 05400022042
05400028496 05400033166 05400034790 05400037495 05400038776 05400040523
05400047674 05400048248 05400049237 05400049834 05400053627 05400054156
05400055485 05400055770 05400057300 05400058964 05400059956 05400060743
05400062459 05400067703 05400072273 05400076481 05400216948 05500003079
05500006796 05500008806 05500012039 05500014375 05500017761 05500021118
05500022399 05500023407 05500024135 05500024190 05500027749 05500032681
05500173451 05500303477 05600037761 05600038251 05600038964 05600051191
05600063115 05600267737 05600553831 05700064077 05700071202 05900072869
06100007818 06100009131 06100011935 06100013662 06100016486 06337850001
06400007916 06400011981 06400014372 06486186001 06500162568 06800008448
06800245196 06843739551 06900069184 07000007872 07100018031 07100063262
07400001254 07600000691 07700009346 07800000968 07800002361 08016809001
08100002398 08498619001 08800003986 08900001310 08900005064 08952698001
09000117963 09000169133 09010011235 09022066011 09300006239 09300035357
09421581768 09500008222 09700003030 09700179110 09900017864 10061805811
10100178199 10201116357 10462157001 10491297001 10621581792 10983439110
11700000658 12019831001 12300074628 22321581834 22721581818 40200401324
40200452735 40200639953 40200700675 90001200901
'''.split())
def compact(number):
"""Convert the number to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace."""
return clean(number, ' -').strip()
def validate(number):
"""Checks to see if the number provided is a valid cedula."""
number = compact(number)
if len(number) != 11:
raise InvalidLength()
if not number.isdigit():
raise InvalidFormat()
if number in whitelist:
return number
return luhn.validate(number)
def is_valid(number):
"""Checks to see if the number provided is a valid cedula."""
try:
return bool(validate(number))
except ValidationError:
return False
def format(number):
"""Reformat the passed number to the standard format."""
number = compact(number)
return '-'.join((number[:3], number[3:-1], number[-1]))

View file

@ -0,0 +1,79 @@
# rnc.py - functions for handling Dominican Republic tax registration
#
# 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
"""RNC (Registro Nacional del Contribuyente, Dominican Republic tax number).
The RNC is the Dominican Republic taxpayer registration number for
institutions. The number consists of 9 digits.
>>> validate('1-01-85004-3')
'101850043'
>>> validate('1018A0043')
Traceback (most recent call last):
...
InvalidFormat: ...
>>> validate('101850042')
Traceback (most recent call last):
...
InvalidChecksum: ...
>>> format('131246796')
'1-31-24679-6'
"""
from stdnum.exceptions import *
from stdnum.util import clean
def compact(number):
"""Convert the number to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace."""
return clean(number, ' -').strip()
def calc_check_digit(number):
"""Calculate the check digit."""
weights = (7, 9, 8, 6, 5, 4, 3, 2)
check = sum(w * int(n) for w, n in zip(weights, number)) % 11
return str((10 - check) % 9 + 1)
def validate(number):
"""Checks to see if the number provided is a valid RNC."""
number = compact(number)
if len(number) != 9:
raise InvalidLength()
if not number.isdigit():
raise InvalidFormat()
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 RNC."""
try:
return bool(validate(number))
except ValidationError:
return False
def format(number):
"""Reformat the passed number to the standard format."""
number = compact(number)
return '-'.join((number[:1], number[1:3], number[3:-1], number[-1]))

View file

@ -0,0 +1,69 @@
# ean.py - functions for handling EANs
#
# Copyright (C) 2011, 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
# 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
"""EAN (International Article Number).
Module for handling EAN (International Article Number) codes. This
module handles numbers EAN-13, EAN-8 and UPC (12-digit) format.
>>> validate('73513537')
'73513537'
>>> validate('978-0-471-11709-4') # EAN-13 format
'9780471117094'
"""
from stdnum.exceptions import *
from stdnum.util import clean
def compact(number):
"""Convert the EAN to the minimal representation. This strips the number
of any valid separators and removes surrounding whitespace."""
return clean(number, ' -').strip()
def calc_check_digit(number):
"""Calculate the EAN check digit for 13-digit numbers. The number passed
should not have the check bit included."""
return str((10 - sum((3 - 2 * (i % 2)) * int(n)
for i, n in enumerate(reversed(number)))) % 10)
def validate(number):
"""Checks to see if the number provided is a valid EAN-13. This checks
the length and the check bit but does not check whether a known GS1
Prefix and company identifier are referenced."""
number = compact(number)
if not number.isdigit():
raise InvalidFormat()
if len(number) not in (13, 12, 8):
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 EAN-13. This checks
the length and the check bit but does not check whether a known GS1
Prefix and company identifier are referenced."""
try:
return bool(validate(number))
except ValidationError:
return False

View file

@ -0,0 +1,24 @@
# __init__.py - collection of Ecuadorian numbers
# coding: utf-8
#
# Copyright (C) 2014 Jonathan Finlay
#
# 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 Ecuadorian numbers."""
# provide vat as an alias
from stdnum.ec import ruc as vat

View file

@ -0,0 +1,78 @@
# ci.py - functions for handling Ecuadorian personal identity codes
# coding: utf-8
#
# Copyright (C) 2014 Jonathan Finlay
# Copyright (C) 2014 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
"""CI (Cédula de identidad, Ecuadorian personal identity code).
The CI is a 10 digit number used to identify Ecuadorian citizens.
>>> validate('171430710-3')
'1714307103'
>>> validate('1714307104') # invalid check digit
Traceback (most recent call last):
...
InvalidChecksum: ...
>>> validate('171430710') # digit missing
Traceback (most recent call last):
...
InvalidLength: ...
"""
from stdnum.exceptions import *
from stdnum.util import clean
def compact(number):
"""Convert the number to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace."""
return clean(number, ' -').upper().strip()
def _checksum(number):
"""Calculate a checksum over the number."""
fold = lambda x: x - 9 if x > 9 else x
return sum(fold((2 - (i % 2)) * int(n))
for i, n in enumerate(number)) % 10
def validate(number):
"""Checks to see if the number provided is a valid CI number. This
checks the length, formatting and check digit."""
number = compact(number)
if len(number) != 10:
raise InvalidLength()
if not number.isdigit():
raise InvalidFormat()
if number[:2] < '01' or number[:2] > '24':
raise InvalidComponent() # invalid province code
if number[2] > '5':
raise InvalidComponent() # third digit wrong
if _checksum(number) != 0:
raise InvalidChecksum()
return number
def is_valid(number):
"""Checks to see if the number provided is a valid CI number. This
checks the length, formatting and check digit."""
try:
return bool(validate(number))
except ValidationError:
return False

View file

@ -0,0 +1,93 @@
# ruc.py - functions for handling Ecuadorian fiscal numbers
# coding: utf-8
#
# Copyright (C) 2014 Jonathan Finlay
# 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
# 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
"""RUC (Registro Único de Contribuyentes, Ecuadorian company tax number).
The RUC is a tax identification number for legal entities. It has 13 digits
where the third digit is a number denoting the type of entity.
>>> validate('1792060346-001')
'1792060346001'
>>> validate('1763154690001') # invalid check digit
Traceback (most recent call last):
...
InvalidChecksum: ...
>>> validate('179206034601') # too short
Traceback (most recent call last):
...
InvalidLength: ...
"""
from stdnum.ec import ci
from stdnum.exceptions import *
__all__ = ['compact', 'validate', 'is_valid']
# use the same compact function as CI
compact = ci.compact
def _checksum(number, weights):
"""Calculate a checksum over the number given the weights."""
return sum(w * int(n) for w, n in zip(weights, number)) % 11
def validate(number):
"""Checks to see if the number provided is a valid RUC number. This
checks the length, formatting, check digit and check sum."""
number = compact(number)
if len(number) != 13:
raise InvalidLength()
if not number.isdigit():
raise InvalidFormat()
if number[:2] < '01' or number[:2] > '24':
raise InvalidComponent() # invalid province code
if number[2] < '6':
# 0..5 = natural RUC: CI plus establishment number
if number[-3:] == '000':
raise InvalidComponent() # establishment number wrong
ci.validate(number[:10])
elif number[2] == '6':
# 6 = public RUC
if number[-4:] == '0000':
raise InvalidComponent() # establishment number wrong
if _checksum(number[:9], (3, 2, 7, 6, 5, 4, 3, 2, 1)) != 0:
raise InvalidChecksum()
elif number[2] == '9':
# 9 = juridical RUC
if number[-3:] == '000':
raise InvalidComponent() # establishment number wrong
if _checksum(number[:10], (4, 3, 2, 7, 6, 5, 4, 3, 2, 1)) != 0:
raise InvalidChecksum()
else:
raise InvalidComponent() # third digit wrong
return number
def is_valid(number):
"""Checks to see if the number provided is a valid RUC number. This
checks the length, formatting and check digit."""
try:
return bool(validate(number))
except ValidationError:
return False

View file

@ -0,0 +1,24 @@
# __init__.py - collection of Estonian numbers
# coding: utf-8
#
# Copyright (C) 2012 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 Estonian numbers."""
# provide vat as an alias
from stdnum.ee import kmkr as vat

View file

@ -0,0 +1,113 @@
# ik.py - functions for handling Estonian Personal ID numbers (IK)
# coding: utf-8
#
# Copyright (C) 2015 Tomas Karasek
# 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
"""Isikukood (Estonian Personcal ID number).
The number consists of 11 digits: the first indicates the gender and century
the person was born in, the following 6 digits the birth date, followed by a
3 digit serial and a check digit.
>>> validate('36805280109')
'36805280109'
>>> validate('36805280108') # incorrect check digit
Traceback (most recent call last):
...
InvalidChecksum: ...
>>> get_birth_date('36805280109')
datetime.date(1968, 5, 28)
"""
import datetime
from stdnum.util import clean
from stdnum.exceptions import *
def compact(number):
"""Convert the number to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace."""
return clean(number, ' ').strip()
def get_birth_date(number):
"""Split the date parts from the number and return the birth date."""
number = compact(number)
if number[0] in '12':
century = 1800
elif number[0] in '34':
century = 1900
elif number[0] in '56':
century = 2000
elif number[0] in '78':
century = 2100
else:
raise InvalidComponent()
year = century + int(number[1:3])
month = int(number[3:5])
day = int(number[5:7])
try:
return datetime.date(year, month, day)
except ValueError:
raise InvalidComponent()
def get_gender(number):
"""Get the person's birth gender ('M' or 'F')."""
number = compact(number)
if number[0] in '1357':
return 'M'
elif number[0] in '2468':
return 'F'
else:
raise InvalidComponent()
def calc_check_digit(number):
"""Calculate the check digit."""
check = sum(((i % 9) + 1) * int(n)
for i, n in enumerate(number[:-1])) % 11
if check == 10:
check = sum((((i + 2) % 9) + 1) * int(n)
for i, n in enumerate(number[:-1])) % 11
return str(check % 10)
def validate(number):
"""Checks if the number provided is valid. This checks the length,
formatting, embedded date and check digit."""
number = compact(number)
if not number.isdigit():
raise InvalidFormat()
if len(number) != 11:
raise InvalidLength()
get_birth_date(number)
if number[-1] != calc_check_digit(number):
raise InvalidChecksum()
return number
def is_valid(number):
"""Checks if the number provided is valid. This checks the length,
formatting, embedded date and check digit."""
try:
return bool(validate(number))
except ValidationError:
return False

View file

@ -0,0 +1,71 @@
# kmkr.py - functions for handling Estonian VAT numbers
# coding: utf-8
#
# 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
# 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
"""KMKR (Käibemaksukohuslase, Estonian VAT number).
>>> compact('EE 100 931 558')
'100931558'
>>> validate('100594102')
'100594102'
>>> validate('100594103') # incorrect check digit
Traceback (most recent call last):
...
InvalidChecksum: ...
"""
from stdnum.exceptions import *
from stdnum.util import clean
def compact(number):
"""Convert the number to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace."""
number = clean(number, ' ').upper().strip()
if number.startswith('EE'):
number = number[2:]
return number
def checksum(number):
"""Calculate the checksum."""
weights = (3, 7, 1, 3, 7, 1, 3, 7, 1)
return sum(w * int(n) for w, n in zip(weights, number)) % 10
def validate(number):
"""Checks to see if the number provided is a valid VAT number. This
checks the length, formatting and check digit."""
number = compact(number)
if not number.isdigit():
raise InvalidFormat()
if len(number) != 9:
raise InvalidLength()
if checksum(number) != 0:
raise InvalidChecksum()
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

View file

@ -0,0 +1,24 @@
# __init__.py - collection of Spanish numbers
# coding: utf-8
#
# Copyright (C) 2012 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 Spanish numbers."""
# provide vat as an alias
from stdnum.es import nif as vat

View file

@ -0,0 +1,108 @@
# cif.py - functions for handling Spanish fiscal numbers
# coding: utf-8
#
# 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
# 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
"""CIF (Certificado de Identificación Fiscal, Spanish company tax number).
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).
>>> validate('J99216582')
'J99216582'
>>> 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', 'validate', 'is_valid', 'split']
# use the same compact function as DNI
compact = dni.compact
def calc_check_digits(number):
"""Calculate the check digits for the specified number. The number
passed should not have the check digit included. This function returns
both the number and character check digit candidates."""
check = luhn.calc_check_digit(number[1:])
return check + 'JABCDEFGHI'[int(check)]
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:-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)
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):
"""Split the provided number into a letter to define the type of
organisation, two digits that specify a province, a 5 digit sequence
number within the province and a check digit."""
number = compact(number)
return number[0], number[1:3], number[3:8], number[8:]

View file

@ -0,0 +1,76 @@
# dni.py - functions for handling Spanish personal identity codes
# coding: utf-8
#
# 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
# 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
"""DNI (Documento nacional de identidad, Spanish personal identity codes).
The DNI is a 9 digit number used to identify Spanish citizens. The last
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.
>>> validate('54362315-K')
'54362315K'
>>> 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
def compact(number):
"""Convert the number to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace."""
return clean(number, ' -').upper().strip()
def calc_check_digit(number):
"""Calculate the check digit. The number passed should not have the
check digit included."""
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:
return bool(validate(number))
except ValidationError:
return False

View file

@ -0,0 +1,77 @@
# nie.py - functions for handling Spanish foreigner identity codes
# coding: utf-8
#
# 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
# 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
"""NIE (Número de Identificación de Extranjeros, Spanish foreigner number).
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.
>>> validate('x-2482300w')
'X2482300W'
>>> 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']
# use the same compact function as DNI
compact = dni.compact
def calc_check_digit(number):
"""Calculate the check digit. The number passed should not have the
check digit included."""
# replace XYZ with 012
number = str('XYZ'.index(number[0])) + number[1:]
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 NIE. This checks
the length, formatting and check digit."""
try:
return bool(validate(number))
except ValidationError:
return False

View file

@ -0,0 +1,85 @@
# nif.py - functions for handling Spanish NIF (VAT) numbers
# coding: utf-8
#
# 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
# 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
"""NIF (Número de Identificación Fiscal, Spanish VAT number).
The Spanish VAT number is a 9-digit number where either the first, last
digits or both can be letters.
The number is either a DNI (Documento nacional de identidad, for
Spaniards), a NIE (Número de Identificación de Extranjeros, for
foreigners) or a CIF (Certificado de Identificación Fiscal, for legal
entities and others).
>>> compact('ES B-58378431')
'B58378431'
>>> 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.es import dni, nie, cif
from stdnum.exceptions import *
from stdnum.util import clean
def compact(number):
"""Convert the number to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace."""
number = clean(number, ' -').upper().strip()
if number.startswith('ES'):
number = number[2:]
return number
def validate(number):
"""Checks to see if the number provided is a valid VAT number. This checks
the length, formatting and check digit."""
number = compact(number)
if not number[1:-1].isdigit():
raise InvalidFormat()
if len(number) != 9:
raise InvalidLength()
if number[0].isdigit():
# natural resident
dni.validate(number)
elif number[0] in 'XYZ':
# foreign natural person
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

View file

@ -0,0 +1,21 @@
# __init__.py - collection of European Union numbers
# coding: utf-8
#
# Copyright (C) 2012 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 European Union numbers."""

View file

@ -0,0 +1,76 @@
# at_02.py - functions for handling AT-02 (SEPA Creditor identifier)
#
# Copyright (C) 2014 Sergi Almacellas Abellana
#
# 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
""" SEPA Identifier of the Creditor (AT-02)
This identifier is indicated in the ISO 20022 data element `Creditor Scheme
Identification`. The creditor can be a legal entity, or an association that
is not a legal entity, or a person.
Ther first two digits contain the ISO country code, the nex two are check
digitsi for the ISO 7064 Mod 97, 10 checksum, the next tree contain the
Creditor Bussines Code (or `ZZZ` if no bussness code used) and the remainder
contain the country-specific identifier.
>>> validate('ES23ZZZ47690558N')
'ES23ZZZ47690558N'
>>> validate('ES2300047690558N')
'ES2300047690558N'
>>> compact('ES++()+23ZZZ4//7690558N')
'ES23ZZZ47690558N'
"""
from stdnum.exceptions import *
from stdnum.iso7064 import mod_97_10
from stdnum.util import clean
# the valid characters we have
_alphabet = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
def compact(number):
"""Convert the AT-02 number to the minimal representation. This strips the
number of any valid separators and removes invalid characters."""
return clean(number, ' -/?:().m\'+"').strip().upper()
def _to_base10(number):
"""Prepare the number to its base10 representation so it can be checked
with the ISO 7064 Mod 97, 10 algorithm. That means excluding positions
5 to 7 and moving the first four digits to the end"""
return ''.join(str(_alphabet.index(x)) for x in number[7:] + number[:4])
def validate(number):
"""Checks to see if the number provided is a valid AT-02."""
number = compact(number)
try:
test_number = _to_base10(number)
except Exception:
raise InvalidFormat()
# ensure that checksum is valid
mod_97_10.validate(test_number)
return number
def is_valid(number):
"""Checks to see if the number provided is a valid AT-02."""
try:
return bool(validate(number))
except ValidationError:
return False

View file

@ -0,0 +1,159 @@
# vat.py - functions for handling European VAT numbers
# coding: utf-8
#
# Copyright (C) 2012-2015 Arthur de Jong
# Copyright (C) 2015 Lionel Elie Mamane
#
# 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
"""VAT (European Union VAT number).
The European Union VAT number consists of a 2 letter country code (ISO
3166-1, except Greece which uses EL) followed by a number that is
allocated per country.
The exact format of the numbers varies per country and a country-specific
check is performed on the number using the VAT module that is relevant for
that country.
>>> compact('ATU 57194903')
'ATU57194903'
>>> validate('BE697449992')
'BE0697449992'
>>> validate('FR 61 954 506 077')
'FR61954506077'
>>> guess_country('00449544B01')
['nl']
"""
from stdnum.exceptions import *
from stdnum.util import clean, get_vat_module
country_codes = set([
'at', 'be', 'bg', 'cy', 'cz', 'de', 'dk', 'ee', 'es', 'fi', 'fr', 'gb',
'gr', 'hr', 'hu', 'ie', 'it', 'lt', 'lu', 'lv', 'mt', 'nl', 'pl', 'pt',
'ro', 'se', 'si', 'sk',
])
"""The collection of country codes that are queried. Greece is listed with
a country code of gr while for VAT purposes el is used instead."""
_country_modules = dict()
vies_wsdl = 'http://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl'
"""The WSDL URL of the VAT Information Exchange System (VIES)."""
# a cached version of the suds client for VIES
_vies_client = None
def _get_cc_module(cc):
"""Get the VAT number module based on the country code."""
# Greece uses a "wrong" country code
cc = cc.lower()
if cc == 'el':
cc = 'gr'
if cc not in country_codes:
return
if cc not in _country_modules:
_country_modules[cc] = get_vat_module(cc)
return _country_modules[cc]
def compact(number):
"""Convert the number to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace."""
number = clean(number, '').upper().strip()
module = _get_cc_module(number[:2])
if not module:
raise InvalidComponent()
return number[:2] + module.compact(number[2:])
def validate(number):
"""Checks to see if the number provided is a valid VAT number. This
performs the country-specific check for the number."""
number = clean(number, '').upper().strip()
module = _get_cc_module(number[:2])
if not module:
raise InvalidComponent()
return number[:2] + module.validate(number[2:])
def is_valid(number):
"""Checks to see if the number provided is a valid VAT number. This
performs the country-specific check for the number."""
try:
return bool(validate(number))
except ValidationError:
return False
def guess_country(number):
"""Guess the country code based on the provided number. This checks the
provided number against each of the validation routines and returns
the list of countries for which it is valid. This returns lower case
codes and returns gr (not el) for Greece."""
return [cc
for cc in country_codes
if _get_cc_module(cc).is_valid(number)]
def _get_client(): # pragma: no cover (no tests for this function)
"""Get a SOAP client for performing VIES requests."""
# this function isn't automatically tested because the functions using
# it are not automatically tested
global _vies_client
if not _vies_client:
try:
from urllib import getproxies
except ImportError:
from urllib.request import getproxies
# try suds first
try:
from suds.client import Client
_vies_client = Client(vies_wsdl, proxy=getproxies()).service
except ImportError:
# fall back to using pysimplesoap
from pysimplesoap.client import SoapClient
_vies_client = SoapClient(wsdl=vies_wsdl, proxy=getproxies())
return _vies_client
def check_vies(number): # pragma: no cover (no tests for this function)
"""Queries the online European Commission VAT Information Exchange
System (VIES) for validity of the provided number. Note that the
service has usage limitations (see the VIES website for details).
This returns a dict-like object."""
# this function isn't automatically tested because it would require
# network access for the tests and unnecessarily load the VIES website
number = compact(number)
return _get_client().checkVat(number[:2], number[2:])
def check_vies_approx(number, requester): # pragma: no cover
"""Queries the online European Commission VAT Information Exchange System
(VIES) for validity of the provided number, providing a validity
certificate as proof. You will need to give your own VAT number for this
to work. Note that the service has usage limitations (see the VIES
website for details). This returns a dict-like object."""
# this function isn't automatically tested because it would require
# network access for the tests and unnecessarily load the VIES website
number = compact(number)
requester = compact(requester)
return _get_client.checkVatApprox(
countryCode=number[:2], vatNumber=number[2:],
requesterCountryCode=requester[:2], requesterVatNumber=requester[2:])

View file

@ -0,0 +1,66 @@
# exceptions.py - collection of stdnum exceptions
# coding: utf-8
#
# Copyright (C) 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
# 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 exceptions.
The validation functions of stdnum should raise one of the below exceptions
when validation of the number fails.
"""
class ValidationError(Exception):
"""Top-level error for validating numbers.
This exception should normally not be raised, only subclasses of this
exception."""
def __str__(self):
return getattr(self, 'message', '')
class InvalidFormat(ValidationError):
"""Something is wrong with the format of the number.
This generally means characters or delimiters that are not allowed are
part of the number or required parts are missing."""
message = 'The number has an invalid format.'
class InvalidChecksum(ValidationError):
"""The number's internal checksum or check digit does not match."""
message = "The number's checksum or check digit is invalid."
class InvalidLength(InvalidFormat):
"""The length of the number is wrong."""
message = 'The number has an invalid length.'
class InvalidComponent(ValidationError):
"""One of the parts of the number has an invalid reference.
Some part of the number refers to some external entity like a country
code, a date or a predefined collection of values. The number contains
some invalid reference."""
message = 'One of the parts of the number are invalid or unknown.'

View file

@ -0,0 +1,26 @@
# __init__.py - collection of Finnish numbers
# coding: utf-8
#
# Copyright (C) 2012 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 Finnish numbers."""
# 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

View file

@ -0,0 +1,71 @@
# vat.py - functions for handling Finnish VAT numbers
# coding: utf-8
#
# 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
# 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
"""ALV nro (Arvonlisäveronumero, Finnish VAT number).
The number is an 8-digit code with a weighted checksum.
>>> validate('FI 20774740')
'20774740'
>>> validate('FI 20774741') # invalid check digit
Traceback (most recent call last):
...
InvalidChecksum: ...
"""
from stdnum.exceptions import *
from stdnum.util import clean
def compact(number):
"""Convert the number to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace."""
number = clean(number, ' -').upper().strip()
if number.startswith('FI'):
number = number[2:]
return number
def checksum(number):
"""Calculate the checksum."""
weights = (7, 9, 10, 5, 8, 4, 2, 1)
return sum(w * int(n) for w, n in zip(weights, number)) % 11
def validate(number):
"""Checks to see if the number provided is a valid VAT number. This
checks the length, formatting and check digit."""
number = compact(number)
if not number.isdigit():
raise InvalidFormat()
if len(number) != 8:
raise InvalidLength()
if checksum(number) != 0:
raise InvalidChecksum()
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

View file

@ -0,0 +1,94 @@
# associationid.py - functions for handling Finnish association registry id
# coding: utf-8
#
# Copyright (C) 2015 Holvi Payment Services Oy
# 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
"""Finnish Association Identifier.
The number consists of 1 to 6 digits that are normally separated with a dot
in groups of 0-3 and 0-3 numbers. E.g. 123.123, 12.123, 1.123, 123 or 1.
>>> validate('123.123')
'123123'
>>> validate('1123')
'1123'
>>> validate('123123123')
Traceback (most recent call last):
...
stdnum.exceptions.InvalidLength: The number has an invalid length.
>>> validate('12df')
Traceback (most recent call last):
...
stdnum.exceptions.InvalidFormat: The number has an invalid format.
>>> format('123')
'123'
>>> format('1234')
'1.234'
"""
from stdnum.exceptions import *
from stdnum.util import clean
# a collection of all registered numbers with 2 or less digits
_lownumbers = set((
1, 6, 7, 9, 12, 14, 15, 16, 18, 22, 23, 24, 27, 28, 29, 35, 36, 38, 40,
41, 42, 43, 45, 46, 50, 52, 55, 58, 60, 64, 65, 68, 72, 75, 76, 77, 78,
83, 84, 85, 89, 92))
def compact(number):
"""Convert the number to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace."""
return clean(number, ' -._+').strip()
def validate(number):
"""
Validate the format of a Finnish association register number.
First strip all separators and spaces from the number and then checks
that it has a correct length and is only numeric.
"""
number = compact(number)
if not number.isdigit():
raise InvalidFormat()
if len(number) < 1 or len(number) > 6:
raise InvalidLength()
if len(number) < 3 and int(number) not in _lownumbers:
raise InvalidComponent()
return number
def is_valid(number):
"""Checks to see if the number provided is a valid association register
number. This checks that the format is correct."""
try:
return bool(validate(number))
except ValidationError:
return False
def format(number):
"""Reformat the passed number to the standard format."""
number = compact(number)
if len(number) <= 3:
return number
else:
return number[:-3] + '.' + number[-3:]

View file

@ -0,0 +1,113 @@
# hetu.py - functions for handling Finnish personal identity codes
# coding: utf-8
#
# Copyright (C) 2011 Jussi Judin
# 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
# 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
"""HETU (Henkilötunnus, Finnish personal identity code).
Module for handling Finnish personal identity codes (HETU, Henkilötunnus).
See http://www.vaestorekisterikeskus.fi/default.aspx?id=45 for checksum
calculation details and http://tarkistusmerkit.teppovuori.fi/tarkmerk.htm#hetu1
for historical details.
>>> validate('131052-308T')
'131052-308T'
>>> validate('131052-308U')
Traceback (most recent call last):
...
InvalidChecksum: ...
>>> validate('310252-308Y')
Traceback (most recent call last):
...
InvalidComponent: ...
>>> compact('131052a308t')
'131052A308T'
"""
import re
import datetime
from stdnum.exceptions import *
from stdnum.util import clean
_century_codes = {
'+': 1800,
'-': 1900,
'A': 2000,
}
# Finnish personal identity codes are composed of date part, century
# indicating sign, individual number and control character.
# ddmmyyciiiC
_hetu_re = re.compile(r'^(?P<day>[0123]\d)(?P<month>[01]\d)(?P<year>\d\d)'
r'(?P<century>[-+A])(?P<individual>\d\d\d)'
r'(?P<control>[0-9ABCDEFHJKLMNPRSTUVWXY])$')
def compact(number):
"""Convert the HETU to the minimal representation. This strips
surrounding whitespace and converts it to upper case."""
return clean(number, '').upper().strip()
def _calc_checksum(number):
return '0123456789ABCDEFHJKLMNPRSTUVWXY'[int(number) % 31]
def validate(number):
"""Checks to see if the number provided is a valid HETU. It checks the
format, whether a valid date is given and whether the check digit is
correct."""
number = compact(number)
match = _hetu_re.search(number)
if not match:
raise InvalidFormat()
day = int(match.group('day'))
month = int(match.group('month'))
year = int(match.group('year'))
century = _century_codes[match.group('century')]
individual = int(match.group('individual'))
# check if birth date is valid
try:
datetime.date(century + year, month, day)
except ValueError:
raise InvalidComponent()
# for historical reasons individual IDs start from 002
if individual < 2:
raise InvalidComponent()
checkable_number = '%02d%02d%02d%03d' % (day, month, year, individual)
if match.group('control') != _calc_checksum(checkable_number):
raise InvalidChecksum()
return number
def is_valid(number):
"""Checks to see if the number provided is a valid HETU. It checks the
format, whether a valid date is given and whether the check digit is
correct."""
try:
return bool(validate(number))
except ValidationError:
return False
# This is here just for completeness as there are no different length forms
# of Finnish personal identity codes:
format = compact

View file

@ -0,0 +1,64 @@
# ytunnus.py - functions for handling Finnish business identifiers (y-tunnus)
# coding: utf-8
#
# Copyright (C) 2015 Holvi Payment Services Oy
# 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
"""Y-tunnus (Finnish business identifier).
The number is an 8-digit code with a weighted checksum.
>>> validate('2077474-0')
'20774740'
>>> validate('2077474-1') # invalid check digit
Traceback (most recent call last):
...
InvalidChecksum: ...
>>> format('2077474-0')
'2077474-0'
"""
from stdnum.exceptions import *
from stdnum.fi import alv
def compact(number):
"""Convert the number to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace."""
return alv.compact(number)
def validate(number):
"""Checks to see if the number provided is a valid business identifier.
This checks the length, formatting and check digit."""
return alv.validate(number)
def is_valid(number):
"""Checks to see if the number provided is a valid business identifier.
This checks the length, formatting and check digit."""
try:
return bool(validate(number))
except ValidationError:
return False
def format(number):
"""Reformat the passed number to the standard format."""
number = compact(number)
return number[:7] + '-' + number[7:]

View file

@ -0,0 +1,24 @@
# __init__.py - collection of French numbers
# coding: utf-8
#
# Copyright (C) 2012 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 French numbers."""
# provide vat as an alias
from stdnum.fr import tva as vat

View file

@ -0,0 +1,85 @@
# siren.py - functions for handling French SIREN numbers
# coding: utf-8
#
# 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
# 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
"""SIREN (a French company identification number).
The SIREN (Système d'Identification du Répertoire des Entreprises) is a 9
digit number used to identify French companies. The Luhn checksum is used
to validate the numbers.
>>> compact('552 008 443')
'552008443'
>>> validate('404833048')
'404833048'
>>> validate('404833047')
Traceback (most recent call last):
...
InvalidChecksum: ...
>>> to_tva('443 121 975')
'46 443 121 975'
"""
from stdnum import luhn
from stdnum.exceptions import *
from stdnum.util import clean
# An online validation function is available but it does not provide an
# automated entry point, has usage restrictions and seems to require
# attribution to the service for any results used.
# http://avis-situation-sirene.insee.fr/
def compact(number):
"""Convert the number to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace."""
return clean(number, ' ').strip()
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 not number.isdigit():
raise InvalidFormat()
if len(number) != 9:
raise InvalidLength()
luhn.validate(number)
return number
def is_valid(number):
"""Checks to see if the number provided is a valid number. This checks
the length, formatting and check digit."""
try:
return bool(validate(number))
except ValidationError:
return False
def to_tva(number):
"""Return a TVA that prepends the two extra check digits to the SIREN."""
# note that this always returns numeric check digits
# it is unclean when the alphabetic ones are used
return '%02d%s%s' % (
int(compact(number) + '12') % 97,
' ' if ' ' in number else '',
number
)

View file

@ -0,0 +1,98 @@
# tva.py - functions for handling French TVA numbers
# coding: utf-8
#
# 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
# 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
"""n° TVA (taxe sur la valeur ajoutée, French VAT number).
The n° TVA (Numéro d'identification à la taxe sur la valeur ajoutée) is the
SIREN (Système dIdentification du Répertoire des Entreprises) prefixed by
two digits. In old style numbers the two digits are numeric, with new
style numbers at least one is a alphabetic.
>>> compact('Fr 40 303 265 045')
'40303265045'
>>> validate('23334175221')
'23334175221'
>>> validate('84 323 140 391')
Traceback (most recent call last):
...
InvalidChecksum: ...
>>> validate('K7399859412') # new-style number
'K7399859412'
>>> validate('4Z123456782') # new-style number starting with digit
'4Z123456782'
>>> validate('IO334175221') # the letters cannot by I or O
Traceback (most recent call last):
...
InvalidFormat: ...
"""
from stdnum.exceptions import *
from stdnum.fr import siren
from stdnum.util import clean
# the valid characters for the first two digits (O and I are missing)
_alphabet = '0123456789ABCDEFGHJKLMNPQRSTUVWXYZ'
def compact(number):
"""Convert the number to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace."""
number = clean(number, ' -.').upper().strip()
if number.startswith('FR'):
number = number[2:]
return number
def validate(number):
"""Checks to see if the number provided is a valid VAT number. This
checks the length, formatting and check digit."""
number = compact(number)
if not all(x in _alphabet for x in number[:2]):
raise InvalidFormat()
if len(number) != 11:
raise InvalidLength()
siren.validate(number[2:])
if number.isdigit():
# all-numeric digits
if int(number[:2]) != (int(number[2:] + '12') % 97):
raise InvalidChecksum()
else:
# one of the first two digits isn't a number
if number[0].isdigit():
check = (
_alphabet.index(number[0]) * 24 +
_alphabet.index(number[1]) - 10)
else:
check = (
_alphabet.index(number[0]) * 34 +
_alphabet.index(number[1]) - 100)
if (int(number[2:]) + 1 + check // 11) % 11 != (check % 11):
raise InvalidChecksum()
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

View file

@ -0,0 +1,21 @@
# __init__.py - collection of United Kingdom numbers
# coding: utf-8
#
# Copyright (C) 2012 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 United Kingdom numbers."""

View file

@ -0,0 +1,86 @@
# sedol.py - functions for handling SEDOL numbers
#
# 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
"""SEDOL number (Stock Exchange Daily Official List number).
The SEDOL number is a security identifier used in the United Kingdom and
Ireland assigned by the London Stock Exchange. A SEDOL is seven characters
in length consisting of six alphanumeric digits, followed by a check digit.
>>> validate('B15KXQ8')
'B15KXQ8'
>>> validate('B15KXQ7')
Traceback (most recent call last):
...
InvalidChecksum: ...
>>> to_isin('B15KXQ8')
'GB00B15KXQ89'
"""
from stdnum.exceptions import *
from stdnum.util import clean
# the letters allowed in an SEDOL (vowels are never used)
_alphabet = '0123456789 BCD FGH JKLMN PQRST VWXYZ'
def compact(number):
"""Convert the number to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace."""
return clean(number, ' ').strip().upper()
def calc_check_digit(number):
"""Calculate the check digits for the number."""
weights = (1, 3, 1, 7, 3, 9)
s = sum(w * _alphabet.index(n) for w, n in zip(weights, number))
return str((10 - s) % 10)
def validate(number):
"""Checks to see if the number provided is valid. This checks the length
and check digit."""
number = compact(number)
if not all(x in _alphabet for x in number):
raise InvalidFormat()
if len(number) != 7:
raise InvalidLength()
if number[0].isdigit() and not number.isdigit():
# new style SEDOLs are supposed to start with a letter, old-style
# numbers should be fully numeric
raise InvalidFormat()
if calc_check_digit(number[:-1]) != number[-1]:
raise InvalidChecksum()
return number
def is_valid(number):
"""Checks to see if the number provided is valid. This checks the length
and check digit."""
try:
return bool(validate(number))
except ValidationError:
return False
def to_isin(number):
"""Convert the number to an ISIN."""
from stdnum import isin
return isin.from_natid('GB', number)

View file

@ -0,0 +1,122 @@
# vat.py - functions for handling United Kingdom VAT numbers
#
# 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
# 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
"""VAT (United Kingdom (and Isle of Man) VAT registration number).
The VAT number can either be a 9-digit standard number, a 12-digit standard
number followed by a 3-digit branch identifier, a 5-digit number for
government departments (first two digits are GD) or a 5-digit number for
health authorities (first two digits are HA). The 9-digit variants use a
weighted checksum.
>>> validate('GB 980 7806 84')
'980780684'
>>> validate('802311781') # invalid check digit
Traceback (most recent call last):
...
InvalidChecksum: ...
>>> format('980780684')
'980 7806 84'
"""
from stdnum.util import clean
from stdnum.exceptions import *
def compact(number):
"""Convert the number to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace."""
number = clean(number, ' -.').upper().strip()
if number.startswith('GB'):
number = number[2:]
return number
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(w * int(n) for w, n in zip(weights, number)) % 97
def validate(number):
"""Checks to see if the number provided is a valid VAT number. This
checks the length, formatting and check digit."""
number = compact(number)
if len(number) == 5:
if not number[2:].isdigit():
raise InvalidFormat()
if number.startswith('GD') and int(number[2:]) < 500:
# government department
pass
elif number.startswith('HA') and int(number[2:]) >= 500:
# health authority
pass
else:
raise InvalidComponent()
elif len(number) == 11 and number[0:6] in ('GD8888', 'HA8888'):
if not number[6:].isdigit():
raise InvalidFormat()
if number.startswith('GD') and int(number[6:9]) < 500:
# government department
pass
elif number.startswith('HA') and int(number[6:9]) >= 500:
# health authority
pass
else:
raise InvalidComponent()
if int(number[6:9]) % 97 != int(number[9:11]):
raise InvalidChecksum()
elif len(number) in (9, 12):
if not number.isdigit():
raise InvalidFormat()
# standard number: nnn nnnn nn
# branch trader: nnn nnnn nn nnn (ignore the last thee digits)
# restarting: 100 nnnn nn
if int(number[:3]) >= 100:
if checksum(number[:9]) not in (0, 42, 55):
raise InvalidChecksum()
else:
if checksum(number[:9]) != 0:
raise InvalidChecksum()
else:
raise InvalidLength()
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
def format(number):
"""Reformat the passed number to the standard format."""
number = compact(number)
if len(number) == 5:
# government department or health authority
return number
if len(number) == 12:
# includes branch number
return number[:3] + ' ' + number[3:7] + ' ' + number[7:9] + ' ' + number[9:]
# standard number: nnn nnnn nn
return number[:3] + ' ' + number[3:7] + ' ' + number[7:]

View file

@ -0,0 +1,21 @@
# __init__.py - collection of Greek numbers
# coding: utf-8
#
# Copyright (C) 2012 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 Greek numbers."""

View file

@ -0,0 +1,78 @@
# vat.py - functions for handling Greek VAT numbers
# coding: utf-8
#
# 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
# 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
"""FPA, ΦΠΑ, ΑΦΜ (Αριθμός Φορολογικού Μητρώου, the Greek VAT number).
The FPA is a 9-digit number with a simple checksum.
>>> compact('GR 23456783')
'023456783'
>>> validate('EL 094259216 ')
'094259216'
>>> validate('EL 123456781')
Traceback (most recent call last):
...
InvalidChecksum: ...
"""
from stdnum.exceptions import *
from stdnum.util import clean
def compact(number):
"""Convert the number to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace."""
number = clean(number, ' -./:').upper().strip()
if number.startswith('EL') or number.startswith('GR'):
number = number[2:]
if len(number) == 8:
number = '0' + number # old format had 8 digits
return number
def calc_check_digit(number):
"""Calculate the check digit. The number passed should not have the
check digit included."""
checksum = 0
for n in number:
checksum = checksum * 2 + int(n)
return str(checksum * 2 % 11 % 10)
def validate(number):
"""Checks to see if the number provided is a valid VAT number. This
checks the length, formatting and check digit."""
number = compact(number)
if not number.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 VAT number. This
checks the length, formatting and check digit."""
try:
return bool(validate(number))
except ValidationError:
return False

View file

@ -0,0 +1,74 @@
# grid.py - functions for handling Global Release Identifier (GRid) numbers
#
# Copyright (C) 2010, 2011, 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
# 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
"""GRid (Global Release Identifier).
The Global Release Identifier is used to identify releases of digital
sound recordings and uses the ISO 7064 Mod 37, 36 algorithm to verify the
correctness of the number.
>>> validate('A12425GABC1234002M')
'A12425GABC1234002M'
>>> validate('Grid: A1-2425G-ABC1234002-M')
'A12425GABC1234002M'
>>> validate('A1-2425G-ABC1234002-Q') # incorrect check digit
Traceback (most recent call last):
...
InvalidChecksum: ...
>>> compact('A1-2425G-ABC1234002-M')
'A12425GABC1234002M'
>>> format('A12425GABC1234002M')
'A1-2425G-ABC1234002-M'
"""
from stdnum.exceptions import *
from stdnum.util import clean
def compact(number):
"""Convert the GRid to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace."""
number = clean(number, ' -').strip().upper()
if number.startswith('GRID:'):
number = number[5:]
return number
def validate(number):
"""Checks to see if the number provided is a valid GRid."""
from stdnum.iso7064 import mod_37_36
number = compact(number)
if len(number) != 18:
raise InvalidLength()
return mod_37_36.validate(number)
def is_valid(number):
"""Checks to see if the number provided is a valid GRid."""
try:
return bool(validate(number))
except ValidationError:
return False
def format(number, separator='-'):
"""Reformat the passed number to the standard format."""
number = compact(number)
number = (number[0:2], number[2:7], number[7:17], number[17:])
return separator.join(x for x in number if x)

View file

@ -0,0 +1,24 @@
# __init__.py - collection of Croatian numbers
# coding: utf-8
#
# Copyright (C) 2012 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 Croatian numbers."""
# provide vat as an alias
from stdnum.hr import oib as vat

View file

@ -0,0 +1,67 @@
# cnp.py - functions for handling Croatian OIB numbers
# coding: utf-8
#
# 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
# 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
"""OIB (Osobni identifikacijski broj, Croatian identification number).
The personal identification number is used to identify persons and legal
entities in Croatia. It has 11 digits (sometimes prefixed by HR), contains
no personal information and uses the ISO 7064 Mod 11, 10 checksum algorithm.
>>> validate('HR 33392005961')
'33392005961'
>>> validate('33392005962') # invalid check digit
Traceback (most recent call last):
...
InvalidChecksum: ...
"""
from stdnum.exceptions import *
from stdnum.iso7064 import mod_11_10
from stdnum.util import clean
def compact(number):
"""Convert the number to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace."""
number = clean(number, ' -').upper().strip()
if number.startswith('HR'):
number = number[2:]
return number
def validate(number):
"""Checks to see if the number provided is a valid OIB number. This
checks the length, formatting and check digit."""
number = compact(number)
if not number.isdigit():
raise InvalidFormat()
if len(number) != 11:
raise InvalidLength()
mod_11_10.validate(number)
return number
def is_valid(number):
"""Checks to see if the number provided is a valid OIB number. This
checks the length, formatting and check digit."""
try:
return bool(validate(number))
except ValidationError:
return False

View file

@ -0,0 +1,24 @@
# __init__.py - collection of Hungarian numbers
# coding: utf-8
#
# Copyright (C) 2012 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 Hungarian numbers."""
# provide vat as an alias
from stdnum.hu import anum as vat

View file

@ -0,0 +1,72 @@
# anum.py - functions for handling Hungarian VAT numbers
# coding: utf-8
#
# 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
# 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
"""ANUM (Közösségi adószám, Hungarian VAT number).
The ANUM is the Hungarian VAT (Közösségi adószám) number. It is an 8-digit
taxpayer registration number that includes a weighted checksum.
>>> validate('HU-12892312')
'12892312'
>>> validate('HU-12892313') # invalid check digit
Traceback (most recent call last):
...
InvalidChecksum: ...
"""
from stdnum.exceptions import *
from stdnum.util import clean
def compact(number):
"""Convert the number to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace."""
number = clean(number, ' -').upper().strip()
if number.startswith('HU'):
number = number[2:]
return 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(w * int(n) for w, n in zip(weights, number)) % 10
def validate(number):
"""Checks to see if the number provided is a valid VAT number. This
checks the length, formatting and check digit."""
number = compact(number)
if not number.isdigit():
raise InvalidFormat()
if len(number) != 8:
raise InvalidLength()
if checksum(number) != 0:
raise InvalidChecksum()
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

View file

@ -0,0 +1,72 @@
# generated from IBAN_Registry.txt, downloaded from
# http://www.swift.com/dsp/resources/documents/IBAN_Registry.txt
AL country="Albania" bban="8!n16!c"
AD country="Andorra" bban="4!n4!n12!c"
AT country="Austria" bban="5!n11!n"
AZ country="Republic of Azerbaijan" bban="4!a20!c"
BH country="Bahrain (Kingdom of)" bban="4!a14!c"
BE country="Belgium" bban="3!n7!n2!n"
BA country="Bosnia and Herzegovina" bban="3!n3!n8!n2!n"
BR country="Brazil" bban="8!n5!n10!n1!a1!c"
BG country="Bulgaria" bban="4!a4!n2!n8!c"
CR country="Costa Rica" bban="3!n14!n"
HR country="Croatia" bban="7!n10!n"
CY country="Cyprus" bban="3!n5!n16!c"
CZ country="Czech Republic" bban="4!n6!n10!n"
DK country="Denmark" bban="4!n9!n1!n"
FO country="Denmark" bban="4!n9!n1!n"
GL country="Denmark" bban="4!n9!n1!n"
DO country="Dominican Republic" bban="4!c20!n"
EE country="Estonia" bban="2!n2!n11!n1!n"
FI country="Finland" bban="6!n7!n1!n"
FR country="France" bban="5!n5!n11!c2!n"
GE country="Georgia" bban="2!a16!n"
DE country="Germany" bban="8!n10!n"
GI country="Gibraltar" bban="4!a15!c"
GR country="Greece" bban="3!n4!n16!c"
GT country="Guatemala" bban="4!c20!c"
HU country="Hungary" bban="3!n4!n1!n15!n1!n"
IS country="Iceland" bban="4!n2!n6!n10!n"
IE country="Ireland" bban="4!a6!n8!n"
IL country="Israel" bban="3!n3!n13!n"
IT country="Italy" bban="1!a5!n5!n12!c"
JO country="Jordan" bban="4!a4!n18!c"
KZ country="Kazakhstan" bban="3!n13!c"
XK country="Republic of Kosovo" bban="4!n10!n2!n"
KW country="Kuwait" bban="4!a22!c"
LV country="Latvia" bban="4!a13!c"
LB country="Lebanon" bban="4!n20!c"
LI country="Liechtenstein (Principality of)" bban="5!n12!c"
LT country="Lithuania" bban="5!n11!n"
LU country="Luxembourg" bban="3!n13!c"
MK country="Macedonia, Former Yugoslav Republic of" bban="3!n10!c2!n"
MT country="Malta" bban="4!a5!n18!c"
MR country="Mauritania" bban="5!n5!n11!n2!n"
MU country="Mauritius" bban="4!a2!n2!n12!n3!n3!a"
MD country="Moldova" bban="2!c18!c"
MC country="Monaco" bban="5!n5!n11!c2!n"
ME country="Montenegro" bban="3!n13!n2!n"
NL country="The Netherlands" bban="4!a10!n"
NO country="Norway" bban="4!n6!n1!n"
PK country="Pakistan" bban="4!a16!c"
PS country="Palestine, State of" bban="4!a21!c"
PL country="Poland" bban="8!n16!n"
PT country="Portugal" bban="4!n4!n11!n2!n"
QA country="Qatar" bban="4!a21!c"
RO country="Romania" bban="4!a16!c"
LC country="Saint Lucia" bban="4!a24n"
SM country="San Marino" bban="1!a5!n5!n12!c"
ST country="Sao Tome And Principe" bban="8!n11!n2!n"
SA country="Saudi Arabia" bban="2!n18!c"
RS country="Serbia" bban="3!n13!n2!n"
SK country="Slovak Republic" bban="4!n6!n10!n"
SI country="Slovenia" bban="5!n8!n2!n"
ES country="Spain" bban="4!n4!n1!n1!n10!n"
SE country="Sweden" bban="3!n16!n1!n"
CH country="Switzerland" bban="5!n12!c"
TL country="Timor-Leste" bban="3!n14!n2!n"
TN country="Tunisia" bban="2!n3!n13!n2!n"
TR country="Turkey" bban="5!n1!n16!c"
AE country="United Arab Emirates" bban="3!n16!n"
GB country="United Kingdom" bban="4!a6!n8!n"
VG country="Virgin Islands, British" bban="4!a16!n"

View file

@ -0,0 +1,115 @@
# iban.py - functions for handling International Bank Account Numbers (IBANs)
#
# Copyright (C) 2011, 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
# 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
"""IBAN (International Bank Account Number).
The IBAN is used to identify bank accounts across national borders. The
first two letters are a country code. The next two digits are check digits
for the ISO 7064 Mod 97, 10 checksum. Each country uses its own format
for the remainder of the number.
Some countries may also use checksum algorithms within their number but
this is currently not checked by this number.
>>> validate('GR16 0110 1050 0000 1054 7023 795')
'GR1601101050000010547023795'
>>> validate('BE31435411161155')
'BE31435411161155'
>>> compact('GR16 0110 1050 0000 1054 7023 795')
'GR1601101050000010547023795'
>>> format('GR1601101050000010547023795')
'GR16 0110 1050 0000 1054 7023 795'
"""
import re
from stdnum import numdb
from stdnum.exceptions import *
from stdnum.iso7064 import mod_97_10
from stdnum.util import clean
# our open copy of the IBAN database
_ibandb = numdb.get('iban')
# the valid characters we have
_alphabet = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
# regular expression to check IBAN structure
_struct_re = re.compile(r'([1-9][0-9]*)!([nac])')
def compact(number):
"""Convert the iban number to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace."""
return clean(number, ' -').strip().upper()
def _to_base10(number):
"""Prepare the number to its base10 representation (also moving the
check digits to the end) so it can be checked with the ISO 7064
Mod 97, 10 algorithm."""
# TODO: find out whether this should be in the mod_97_10 module
return ''.join(str(_alphabet.index(x)) for x in number[4:] + number[:4])
def _struct_to_re(structure):
"""Convert an IBAN structure to a refular expression that can be used
to validate the number."""
def conv(match):
chars = {
'n': '[0-9]',
'a': '[A-Z]',
'c': '[A-Za-z0-9]',
}[match.group(2)]
return '%s{%s}' % (chars, match.group(1))
return re.compile('^%s$' % _struct_re.sub(conv, structure))
def validate(number):
"""Checks to see if the number provided is a valid IBAN."""
number = compact(number)
try:
test_number = _to_base10(number)
except Exception:
raise InvalidFormat()
# ensure that checksum is valid
mod_97_10.validate(test_number)
# look up the number
info = _ibandb.info(number)
# check if the bban part of number has the correct structure
bban = number[4:]
if not _struct_to_re(info[0][1].get('bban', '')).match(bban):
raise InvalidFormat()
# return the compact representation
return number
def is_valid(number):
"""Checks to see if the number provided is a valid IBAN."""
try:
return bool(validate(number))
except ValidationError:
return False
def format(number, separator=' '):
"""Reformat the passed number to the space-separated format."""
number = compact(number)
return separator.join(number[i:i + 4] for i in range(0, len(number), 4))

View file

@ -0,0 +1,21 @@
# __init__.py - collection of Irish numbers
# coding: utf-8
#
# Copyright (C) 2012 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 Irish numbers."""

View file

@ -0,0 +1,91 @@
# pps.py - functions for handling Irish PPS numbers
#
# Copyright (C) 2012, 2013 Arthur de Jong
# Copyright (C) 2014 Olivier Dony
#
# 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
"""PPS No (Personal Public Service Number, Irish personal number).
The Personal Public Service number consists of 7 digits, and one or
two letters. The first letter is a check character.
When present (which should be the case for new numbers as of 2013),
the second letter can be 'A' (for individuals) or 'H' (for
non-individuals, such as limited companies, trusts, partnerships
and unincorporated bodies). Pre-2013 values may have 'W', 'T',
or 'X' as the second letter ; it is ignored by the check.
>>> validate('6433435F') # pre-2013
'6433435F'
>>> validate('6433435FT') # pre-2013 with special final 'T'
'6433435FT'
>>> validate('6433435FW') # pre-2013 format for married women
'6433435FW'
>>> validate('6433435E') # incorrect check digit
Traceback (most recent call last):
...
InvalidChecksum: ...
>>> validate('6433435OA') # 2013 format (personal)
'6433435OA'
>>> validate('6433435IH') # 2013 format (non-personal)
'6433435IH'
>>> validate('6433435VH') # 2013 format (incorrect check)
Traceback (most recent call last):
...
InvalidChecksum: ...
"""
import re
from stdnum.exceptions import *
from stdnum.ie import vat
from stdnum.util import clean
pps_re = re.compile(r'^\d{7}[A-W][AHWTX]?$')
"""Regular expression used to check syntax of PPS numbers."""
def compact(number):
"""Convert the number to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace."""
return clean(number, ' -').upper().strip()
def validate(number):
"""Checks to see if the number provided is a valid PPS number. This
checks the length, formatting and check digit."""
number = compact(number)
if not pps_re.match(number):
raise InvalidFormat()
if len(number) == 9 and number[8] in 'AH':
# new 2013 format
if number[7] != vat.calc_check_digit(number[:7] + number[8:]):
raise InvalidChecksum()
else:
# old format, last letter ignored
if number[7] != vat.calc_check_digit(number[:7]):
raise InvalidChecksum()
return number
def is_valid(number):
"""Checks to see if the number provided is a valid PPS number. This
checks the length, formatting and check digit."""
try:
return bool(validate(number))
except ValidationError:
return False

View file

@ -0,0 +1,91 @@
# vat.py - functions for handling Irish VAT numbers
#
# 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
# 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
"""VAT (Irish VAT number).
The Irish VAT number consists of 8 digits. The last digit is a check
letter, the second digit may be a number, a letter, "+" or "*".
>>> validate('IE 6433435F') # pre-2013 format
'6433435F'
>>> validate('IE 6433435OA') # 2013 format
'6433435OA'
>>> validate('6433435E') # incorrect check digit
Traceback (most recent call last):
...
InvalidChecksum: ...
>>> validate('8D79739I') # old style number
'8D79739I'
>>> validate('8?79739J') # incorrect old style
Traceback (most recent call last):
...
InvalidFormat: ...
"""
from stdnum.exceptions import *
from stdnum.util import clean
def compact(number):
"""Convert the number to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace."""
number = clean(number, ' -').upper().strip()
if number.startswith('IE'):
number = number[2:]
return number
def calc_check_digit(number):
"""Calculate the check digit. The number passed should not have the
check digit included."""
alphabet = 'WABCDEFGHIJKLMNOPQRSTUV'
number = compact(number).zfill(7)
return alphabet[(
sum((8 - i) * int(n) for i, n in enumerate(number[:7])) +
9 * alphabet.index(number[7:])) % 23]
def validate(number):
"""Checks to see if the number provided is a valid VAT number. This checks
the length, formatting and check digit."""
number = compact(number)
if not number[:1].isdigit() or not number[2:7].isdigit():
raise InvalidFormat()
if len(number) not in (8, 9):
raise InvalidLength()
if number[:7].isdigit():
# new system
if number[7] != calc_check_digit(number[:7] + number[8:]):
raise InvalidChecksum()
elif number[1] in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ+*':
# old system
if number[7] != calc_check_digit(number[2:7] + number[0]):
raise InvalidChecksum()
else:
raise InvalidFormat()
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

View file

@ -0,0 +1,106 @@
# imei.py - functions for handling International Mobile Equipment Identity
# (IMEI) numbers
#
# Copyright (C) 2010, 2011, 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
# 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
"""IMEI (International Mobile Equipment Identity).
The IMEI is used to identify mobile phones. The IMEI may optionally
include a check digit which is validated using the Luhn algorithm.
>>> validate('35686800-004141-20')
'3568680000414120'
>>> validate('35-417803-685978-1')
Traceback (most recent call last):
...
InvalidChecksum: ...
>>> compact('35686800-004141-20')
'3568680000414120'
>>> format('354178036859789')
'35-417803-685978-9'
>>> format('35686800-004141', add_check_digit=True)
'35-686800-004141-8'
>>> imei_type('35686800-004141-20')
'IMEISV'
>>> split('35686800-004141')
('35686800', '004141', '')
"""
from stdnum import luhn
from stdnum.exceptions import *
from stdnum.util import clean
def compact(number):
"""Convert the IMEI number to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace."""
return clean(number, ' -').strip().upper()
def validate(number):
"""Checks to see if the number provided is a valid IMEI (or IMEISV)
number."""
number = compact(number)
if not number.isdigit():
raise InvalidFormat()
if len(number) == 15:
# only 15 digit IMEI has check digit
luhn.validate(number)
elif len(number) not in (14, 16):
# neither IMEI without check digit or IMEISV (which doesn't have one)
raise InvalidLength()
return number
def imei_type(number):
"""Check the passed number and returns 'IMEI', 'IMEISV' or None (for
invalid) for checking the type of number passed."""
try:
number = validate(number)
except ValidationError:
return None
if len(number) in (14, 15):
return 'IMEI'
else: # len(number) == 16:
return 'IMEISV'
def is_valid(number):
"""Checks to see if the number provided is a valid IMEI (or IMEISV)
number."""
try:
return bool(validate(number))
except ValidationError:
return False
def split(number):
"""Split the number into a Type Allocation Code (TAC), serial number
and either the checksum (for IMEI) or the software version number (for
IMEISV)."""
number = compact(number)
return (number[:8], number[8:14], number[14:])
def format(number, separator='-', add_check_digit=False):
"""Reformat the passed number to the standard format."""
number = compact(number)
if len(number) == 14 and add_check_digit:
number += luhn.calc_check_digit(number)
number = (number[:2], number[2:8], number[8:14], number[14:])
return separator.join(x for x in number if x)

View file

@ -0,0 +1,85 @@
# imo.py - functions for handling IMO 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
"""IMO number (International Maritime Organization number).
A number used to uniquely identify ships (the hull) for purposes of
registering owners and management companies. The ship identification number
consists of a six-digit sequentially assigned number and a check digit. The
number is usually prefixed with "IMO".
Note that there seem to be a large number of ships with an IMO that does not
have a valid check digit or even have a different length.
>>> validate('IMO 9319466')
'9319466'
>>> validate('IMO 8814275')
'8814275'
>>> validate('8814274')
Traceback (most recent call last):
...
InvalidChecksum: ...
>>> format('8814275')
'IMO 8814275'
"""
from stdnum.exceptions import *
from stdnum.util import clean
def compact(number):
"""Convert the number to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace."""
number = clean(number, ' ').upper().strip()
if number.startswith('IMO'):
number = number[3:]
return number
def calc_check_digit(number):
"""Calculate the check digits for the number."""
return str(sum(int(n) * (7 - i) for i, n in enumerate(number[:6])) % 10)
def validate(number):
"""Checks to see if the number provided is valid. This checks the length
and check digit."""
number = compact(number)
if not number.isdigit():
raise InvalidFormat()
if len(number) != 7:
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 valid. This checks the length
and check digit."""
try:
return bool(validate(number))
except ValidationError:
return False
def format(number):
"""Reformat the passed number to the standard format."""
return 'IMO ' + compact(number)

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,96 @@
# imsi.py - functions for handling International Mobile Subscriber Identity
# (IMSI) numbers
#
# Copyright (C) 2011-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
"""IMSI (International Mobile Subscriber Identity).
The IMSI (International Mobile Subscriber Identity) is used to identify
mobile phone users (the SIM).
>>> validate('429011234567890')
'429011234567890'
>>> validate('439011234567890') # unknown MCC
Traceback (most recent call last):
...
InvalidComponent: ...
>>> split('429011234567890')
('429', '01', '1234567890')
>>> split('310150123456789')
('310', '150', '123456789')
>>> info('460001234567890')['mcc']
'460'
>>> str(info('460001234567890')['country'])
'China'
"""
from stdnum.exceptions import *
from stdnum.util import clean
def compact(number):
"""Convert the IMSI number to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace."""
return clean(number, ' -').strip().upper()
def split(number):
"""Split the specified IMSI into a Mobile Country Code (MCC), a Mobile
Network Code (MNC), a Mobile Station Identification Number (MSIN)."""
from stdnum import numdb
# clean up number
number = compact(number)
# split the number
return tuple(numdb.get('imsi').split(number))
def validate(number):
"""Checks to see if the number provided is a valid IMSI."""
number = compact(number)
if not number.isdigit():
raise InvalidFormat()
if len(number) not in (14, 15):
raise InvalidLength()
if len(split(number)) != 3:
raise InvalidComponent()
return number
def info(number):
"""Return a dictionary of data about the supplied number."""
from stdnum import numdb
# clean up number
number = compact(number)
# split the number
info = dict(number=number)
mcc_info, mnc_info, msin_info = numdb.get('imsi').info(number)
info['mcc'] = mcc_info[0]
info.update(mcc_info[1])
info['mnc'] = mnc_info[0]
info.update(mnc_info[1])
info['msin'] = msin_info[0]
info.update(msin_info[1])
return info
def is_valid(number):
"""Checks to see if the number provided is a valid IMSI."""
try:
return bool(validate(number))
except ValidationError:
return False

View file

@ -0,0 +1,24 @@
# __init__.py - collection of Icelandic numbers
# coding: utf-8
#
# Copyright (C) 2015 Tuomas Toivonen
#
# 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 Icelandic numbers."""
# provide vat as an alias
from stdnum.is_ import vsk as vat

View file

@ -0,0 +1,116 @@
# kennitala.py - functions for handling Icelandic identity codes
# coding: utf-8
#
# Copyright (C) 2015 Tuomas Toivonen
# 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
"""Kennitala (Icelandic personal and organisation identity code).
Module for handling Icelandic personal and organisation identity codes
(kennitala).
>>> validate('450401-3150') # organisation
'4504013150'
>>> validate('120174-3399') # individual
'1201743399'
>>> validate('530575-0299')
Traceback (most recent call last):
...
InvalidChecksum: ...
>>> validate('320174-3399')
Traceback (most recent call last):
...
InvalidComponent: ...
>>> format('1201743399')
'120174-3399'
"""
import re
import datetime
from stdnum.exceptions import *
from stdnum.util import clean
# Icelandic personal and organisation identity codes are composed of
# date part, a dash, two random digits, a checksum, and a century
# indicator where '9' for 1900-1999 and '0' for 2000 and beyond. For
# organisations instead of birth date, the registration date is used,
# and number 4 is added to the first digit.
_kennitala_re = re.compile(
r'^(?P<day>[01234567]\d)(?P<month>[01]\d)(?P<year>\d\d)'
r'(?P<random>\d\d)(?P<control>\d)'
r'(?P<century>[09])$')
def compact(number):
"""Convert the kennitala to the minimal representation. This
strips surrounding whitespace and separation dash, and converts it
to upper case."""
return clean(number, '-').upper().strip()
def checksum(number):
"""Calculate the checksum."""
weights = (3, 2, 7, 6, 5, 4, 3, 2, 1, 0)
return sum(w * int(n) for w, n in zip(weights, number)) % 11
def validate(number):
"""Checks to see if the number provided is a valid kennitala. It
checks the format, whether a valid date is given and whether the
check digit is correct."""
number = compact(number)
match = _kennitala_re.search(number)
if not match:
raise InvalidFormat()
day = int(match.group('day'))
month = int(match.group('month'))
year = int(match.group('year'))
if match.group('century') == '9':
year += 1900
else:
year += 2000
# check if birth date or registration data is valid
try:
if day >= 40: # organisation
datetime.date(year, month, day - 40)
else: # individual
datetime.date(year, month, day)
except ValueError:
raise InvalidComponent()
# validate the checksum
if checksum(number) != 0:
raise InvalidChecksum()
return number
def is_valid(number):
"""Checks to see if the number provided is a valid HETU. It checks the
format, whether a valid date is given and whether the check digit is
correct."""
try:
return bool(validate(number))
except ValidationError:
return False
def format(number):
"""Reformat the passed number to the standard format."""
number = compact(number)
return number[:6] + '-' + number[6:]

View file

@ -0,0 +1,63 @@
# vsk.py - functions for handling Icelandic VAT numbers
# coding: utf-8
#
# Copyright (C) 2015 Tuomas Toivonen
#
# 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
"""VSK number (Virðisaukaskattsnúmer, Icelandic VAT number).
The Icelandic VAT number is five or six digits.
>>> validate('IS 00621')
'00621'
>>> validate('IS 0062199')
Traceback (most recent call last):
...
InvalidLength: ...
"""
from stdnum.exceptions import *
from stdnum.util import clean
def compact(number):
"""Convert the number to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace."""
number = clean(number, ' ').upper().strip()
if number.startswith('IS'):
number = number[2:]
return number
def validate(number):
"""Checks to see if the number provided is a valid VAT number. This
checks the length and formatting."""
number = compact(number)
if not number.isdigit():
raise InvalidFormat()
if len(number) not in (5, 6):
raise InvalidLength()
return number
def is_valid(number):
"""Checks to see if the number provided is a valid VAT number. This
checks the length and formatting."""
try:
return bool(validate(number))
except ValidationError:
return False

View file

@ -0,0 +1,156 @@
# isan.py - functions for handling International Standard Audiovisual Numbers
# (ISANs)
#
# Copyright (C) 2010, 2011, 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
# 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
"""ISAN (International Standard Audiovisual Number).
The ISAN (International Standard Audiovisual Number) is used to identify
audiovisual works.
The number is hexadecimal and can consists of at least a root identifier,
and an episode or part. After that an optional check digit, optional
version and optionally another check digit can be provided. The check
digits are validated using the ISO 7064 Mod 37, 36 algorithm.
>>> validate('000000018947000000000000')
'000000018947000000000000'
>>> compact('0000-0000-D07A-0090-Q-0000-0000-X')
'00000000D07A009000000000'
>>> validate('0000-0001-8CFA-0000-I-0000-0000-K')
'000000018CFA0000I00000000K'
>>> validate('0000-0001-8CFA-0000-A-0000-0000-K')
Traceback (most recent call last):
...
InvalidChecksum: ...
>>> format('000000018947000000000000')
'0000-0001-8947-0000-8-0000-0000-D'
>>> to_urn('00000000D07A009000000000')
'URN:ISAN:0000-0000-D07A-0090-Q-0000-0000-X'
>>> to_xml('1881-66C7-3420-6541-Y-9F3A-0245-O')
'<ISAN root="1881-66C7-3420" episode="6541" version="9F3A-0245" />'
"""
from stdnum.exceptions import *
from stdnum.iso7064 import mod_37_36
from stdnum.util import clean
def split(number):
"""Splits the number into a root, an episode or part, a check digit a
version and another check digit. If any of the parts are missing an
empty string is returned."""
number = clean(number, ' -').strip().upper()
if len(number) == 17 or len(number) == 26:
return number[0:12], number[12:16], number[16], number[17:25], number[25:]
elif len(number) > 16:
return number[0:12], number[12:16], '', number[16:24], number[24:]
else:
return number[0:12], number[12:16], number[16:], '', ''
def compact(number, strip_check_digits=True):
"""Convert the ISAN to the minimal representation. This strips the number
of any valid separators and removes surrounding whitespace. The check
digits are removed by default."""
number = list(split(number))
if strip_check_digits:
number[2] = number[4] = ''
return ''.join(number)
def validate(number, strip_check_digits=False, add_check_digits=False):
"""Checks to see if the number provided is a valid ISAN. If check digits
are present in the number they are validated. If strip_check_digits is
True any existing check digits will be removed (after checking). If
add_check_digits is True the check digit will be added if they are not
present yet."""
(root, episode, check1, version, check2) = split(number)
# check digits used
for x in root + episode + version:
if x not in '0123456789ABCDEF':
raise InvalidFormat()
# check length of all components
if len(root) != 12 or len(episode) != 4 or len(check1) not in (0, 1) or \
len(version) not in (0, 8) or len(check1) not in (0, 1):
raise InvalidLength()
# allow removing check digits
if strip_check_digits:
check1 = check2 = ''
# check check digits
if check1:
mod_37_36.validate(root + episode + check1)
if check2:
mod_37_36.validate(root + episode + version + check2)
# add check digits
if add_check_digits and not check1:
check1 = mod_37_36.calc_check_digit(root + episode)
if add_check_digits and not check2 and version:
check2 = mod_37_36.calc_check_digit(root + episode + version)
return root + episode + check1 + version + check2
def is_valid(number):
"""Checks to see if the number provided is a valid ISAN. If check digits
are present in the number they are validated."""
try:
return bool(validate(number))
except ValidationError:
return False
def format(number, separator='-', strip_check_digits=False, add_check_digits=True):
"""Reformat the passed number to the standard format. If
add_check_digits is True the check digit will be added if they are not
present yet. If both strip_check_digits and add_check_digits are True the
check digits will be recalculated."""
(root, episode, check1, version, check2) = split(number)
if strip_check_digits:
check1 = check2 = ''
if add_check_digits and not check1:
check1 = mod_37_36.calc_check_digit(root + episode)
if add_check_digits and not check2 and version:
check2 = mod_37_36.calc_check_digit(root + episode + version)
number = [root[i:i + 4] for i in range(0, 12, 4)] + [episode]
if check1:
number.append(check1)
if version:
number.extend((version[0:4], version[4:]))
if check2:
number.append(check2)
return separator.join(number)
def to_binary(number):
"""Convert the number to its binary representation (without the check
digits)."""
from binascii import a2b_hex
return a2b_hex(compact(number, strip_check_digits=True))
def to_xml(number):
"""Returns the XML form of the ISAN as a string."""
number = format(number, strip_check_digits=True, add_check_digits=False)
return '<ISAN root="%s" episode="%s" version="%s" />' % (
number[0:14], number[15:19], number[20:])
def to_urn(number):
"""Returns the URN representation of the ISAN."""
return 'URN:ISAN:' + format(number, add_check_digits=True)

View file

@ -0,0 +1,483 @@
# generated from RangeMessage.xml, downloaded from
# https://www.isbn-international.org/export_rangemessage.xml
# file serial e055fb55-2661-4102-a6dc-6885d2dab806
# file date Thu, 3 Sep 2015 12:56:52 CEST
978
0-5,600-649,7-7,80-94,950-989,9900-9989,99900-99999
0 agency="English language"
00-19,200-699,7000-8499,85000-89999,900000-949999,9500000-9999999
1 agency="English language"
00-09,100-399,4000-5499,55000-86979,869800-998999,9990000-9999999
2 agency="French language"
00-19,200-349,35000-39999,400-699,7000-8399,84000-89999,900000-949999
9500000-9999999
3 agency="German language"
00-02,030-033,0340-0369,03700-03999,04-19,200-699,7000-8499,85000-89999
900000-949999,9500000-9539999,95400-96999,9700000-9899999,99000-99499
99500-99999
4 agency="Japan"
00-19,200-699,7000-8499,85000-89999,900000-949999,9500000-9999999
5 agency="former U.S.S.R"
00000-00499,0050-0099,01-19,200-420,4210-4299,430-430,4310-4399,440-440
4410-4499,450-699,7000-8499,85000-89999,900000-909999,91000-91999
9200-9299,93000-94999,9500000-9500999,9501-9799,98000-98999
9900000-9909999,9910-9999
600 agency="Iran"
00-09,100-499,5000-8999,90000-99999
601 agency="Kazakhstan"
00-19,200-699,7000-7999,80000-84999,85-99
602 agency="Indonesia"
00-07,0800-0899,0900-1099,1100-1199,1200-1399,14000-14999,1500-1699
17000-17999,18000-18999,19000-19999,200-674,6750-6999,70000-74999
7500-7999,8000-9499,95000-99999
603 agency="Saudi Arabia"
00-04,05-49,500-799,8000-8999,90000-99999
604 agency="Vietnam"
0-4,50-89,900-979,9800-9999
605 agency="Turkey"
01-02,030-039,04-09,100-399,4000-5999,60000-89999,9000-9999
606 agency="Romania"
0-0,10-49,500-799,8000-9199,92000-99999
607 agency="Mexico"
00-39,400-749,7500-9499,95000-99999
608 agency="Macedonia"
0-0,10-19,200-449,4500-6499,65000-69999,7-9
609 agency="Lithuania"
00-39,400-799,8000-9499,95000-99999
611 agency="Thailand"
612 agency="Peru"
00-29,300-399,4000-4499,45000-49999,50-99
613 agency="Mauritius"
0-9
614 agency="Lebanon"
00-39,400-799,8000-9499,95000-99999
615 agency="Hungary"
00-09,100-499,5000-7999,80000-89999
616 agency="Thailand"
00-19,200-699,7000-8999,90000-99999
617 agency="Ukraine"
00-49,500-699,7000-8999,90000-99999
618 agency="Greece"
00-19,200-499,5000-7999,80000-99999
619 agency="Bulgaria"
00-14,150-699,7000-8999,90000-99999
620 agency="Mauritius"
0-9
621 agency="Philippines"
00-29,400-599,8000-8999,95000-99999
7 agency="China, People's Republic"
00-09,100-499,5000-7999,80000-89999,900000-999999
80 agency="former Czechoslovakia"
00-19,200-699,7000-8499,85000-89999,900000-999999
81 agency="India"
00-19,200-699,7000-8499,85000-89999,900000-999999
82 agency="Norway"
00-19,200-689,690000-699999,7000-8999,90000-98999,990000-999999
83 agency="Poland"
00-19,200-599,60000-69999,7000-8499,85000-89999,900000-999999
84 agency="Spain"
00-13,140-149,15000-19999,200-699,7000-8499,85000-89999,9000-9199
920000-923999,92400-92999,930000-949999,95000-96999,9700-9999
85 agency="Brazil"
00-19,200-549,5500-5999,60000-69999,7000-8499,85000-89999,900000-959999
96-97,98000-99999
86 agency="former Yugoslavia"
00-29,300-599,6000-7999,80000-89999,900000-999999
87 agency="Denmark"
00-29,400-649,7000-7999,85000-94999,970000-999999
88 agency="Italy"
00-19,200-599,6000-8499,85000-89999,900000-909999,910-929,9300-9399
940000-949999,95000-99999
89 agency="Korea, Republic"
00-24,250-549,5500-8499,85000-94999,950000-969999,97000-98999,990-999
90 agency="Netherlands"
00-19,200-499,5000-6999,70000-79999,800000-849999,8500-8999,90-90,94-94
91 agency="Sweden"
0-1,20-49,500-649,7000-7999,85000-94999,970000-999999
92 agency="International NGO Publishers and EU Organizations"
0-5,60-79,800-899,9000-9499,95000-98999,990000-999999
93 agency="India"
00-09,100-499,5000-7999,80000-94999,950000-999999
94 agency="Netherlands"
000-599,6000-8999,90000-99999
950 agency="Argentina"
00-49,500-899,9000-9899,99000-99999
951 agency="Finland"
0-1,20-54,550-889,8900-9499,95000-99999
952 agency="Finland"
00-19,200-499,5000-5999,60-65,6600-6699,67000-69999,7000-7999,80-94
9500-9899,99000-99999
953 agency="Croatia"
0-0,10-14,150-509,51-54,55000-59999,6000-9499,95000-99999
954 agency="Bulgaria"
00-28,2900-2999,300-799,8000-8999,90000-92999,9300-9999
955 agency="Sri Lanka"
0000-1999,20-40,41000-43999,44000-44999,4500-4999,50000-54999,550-749
7500-7999,8000-9499,95000-99999
956 agency="Chile"
00-19,200-699,7000-9999
957 agency="Taiwan"
00-02,0300-0499,05-19,2000-2099,21-27,28000-30999,31-43,440-819
8200-9699,97000-99999
958 agency="Colombia"
00-56,57000-59999,600-799,8000-9499,95000-99999
959 agency="Cuba"
00-19,200-699,7000-8499,85000-99999
960 agency="Greece"
00-19,200-659,6600-6899,690-699,7000-8499,85000-92999,93-93,9400-9799
98000-99999
961 agency="Slovenia"
00-19,200-599,6000-8999,90000-94999
962 agency="Hong Kong, China"
00-19,200-699,7000-8499,85000-86999,8700-8999,900-999
963 agency="Hungary"
00-19,200-699,7000-8499,85000-89999,9000-9999
964 agency="Iran"
00-14,150-249,2500-2999,300-549,5500-8999,90000-96999,970-989,9900-9999
965 agency="Israel"
00-19,200-599,7000-7999,90000-99999
966 agency="Ukraine"
00-12,130-139,14-14,1500-1699,170-199,2000-2789,279-289,2900-2999
300-699,7000-8999,90000-90999,910-949,95000-97999,980-999
967 agency="Malaysia"
00-00,0100-0999,10000-19999,300-499,5000-5999,60-89,900-989,9900-9989
99900-99999
968 agency="Mexico"
01-39,400-499,5000-7999,800-899,9000-9999
969 agency="Pakistan"
0-1,20-22,23000-23999,24-39,400-749,7500-9999
970 agency="Mexico"
01-59,600-899,9000-9099,91000-96999,9700-9999
971 agency="Philippines"
000-015,0160-0199,02-02,0300-0599,06-49,500-849,8500-9099,91000-95999
9600-9699,97-98,9900-9999
972 agency="Portugal"
0-1,20-54,550-799,8000-9499,95000-99999
973 agency="Romania"
0-0,100-169,1700-1999,20-54,550-759,7600-8499,85000-88999,8900-9499
95000-99999
974 agency="Thailand"
00-19,200-699,7000-8499,85000-89999,90000-94999,9500-9999
975 agency="Turkey"
00000-01999,02-24,250-599,6000-9199,92000-98999,990-999
976 agency="Caribbean Community"
0-3,40-59,600-799,8000-9499,95000-99999
977 agency="Egypt"
00-19,200-499,5000-6999,700-849,85000-89999,90-99
978 agency="Nigeria"
000-199,2000-2999,30000-79999,8000-8999,900-999
979 agency="Indonesia"
000-099,1000-1499,15000-19999,20-29,3000-3999,400-799,8000-9499
95000-99999
980 agency="Venezuela"
00-19,200-599,6000-9999
981 agency="Singapore"
00-16,17000-19999,200-299,3000-3099,310-399,4000-9999
982 agency="South Pacific"
00-09,100-699,70-89,9000-9799,98000-99999
983 agency="Malaysia"
00-01,020-199,2000-3999,40000-44999,45-49,50-79,800-899,9000-9899
99000-99999
984 agency="Bangladesh"
00-39,400-799,8000-8999,90000-99999
985 agency="Belarus"
00-39,400-599,6000-8999,90000-99999
986 agency="Taiwan"
00-11,120-559,5600-7999,80000-99999
987 agency="Argentina"
00-09,1000-1999,20000-29999,30-35,3600-3999,4000-4199,42-43,4400-4499
45000-48999,4900-4999,500-899,9000-9499,95000-99999
988 agency="Hong Kong, China"
00-11,12000-14999,15000-16999,17000-19999,200-769,77000-79999,8000-9699
97000-99999
989 agency="Portugal"
0-1,20-54,550-799,8000-9499,95000-99999
9924 agency="Cambodia"
30-39,500-649,9000-9999
9925 agency="Cyprus"
0-2,30-54,550-734,7350-9999
9926 agency="Bosnia and Herzegovina"
0-1,20-39,400-799,8000-9999
9927 agency="Qatar"
00-09,100-399,4000-4999
9928 agency="Albania"
00-09,100-399,4000-4999
9929 agency="Guatemala"
0-3,40-54,550-799,8000-9999
9930 agency="Costa Rica"
00-49,500-939,9400-9999
9931 agency="Algeria"
00-29,300-899,9000-9999
9932 agency="Lao People's Democratic Republic"
00-39,400-849,8500-9999
9933 agency="Syria"
0-0,10-39,400-899,9000-9999
9934 agency="Latvia"
0-0,10-49,500-799,8000-9999
9935 agency="Iceland"
0-0,10-39,400-899,9000-9999
9936 agency="Afghanistan"
0-1,20-39,400-799,8000-9999
9937 agency="Nepal"
0-2,30-49,500-799,8000-9999
9938 agency="Tunisia"
00-79,800-949,9500-9999
9939 agency="Armenia"
0-4,50-79,800-899,9000-9999
9940 agency="Montenegro"
0-1,20-49,500-899,9000-9999
9941 agency="Georgia"
0-0,10-39,400-899,9000-9999
9942 agency="Ecuador"
00-84,8500-8999,900-984,9850-9999
9943 agency="Uzbekistan"
00-29,300-399,4000-9749,975-999
9944 agency="Turkey"
0000-0999,100-499,5000-5999,60-69,700-799,80-89,900-999
9945 agency="Dominican Republic"
00-00,010-079,08-39,400-569,57-57,580-849,8500-9999
9946 agency="Korea, P.D.R."
0-1,20-39,400-899,9000-9999
9947 agency="Algeria"
0-1,20-79,800-999
9948 agency="United Arab Emirates"
00-39,400-849,8500-9999
9949 agency="Estonia"
0-0,10-39,400-749,75-89,9000-9999
9950 agency="Palestine"
00-29,300-849,8500-9999
9951 agency="Kosova"
00-39,400-849,8500-9999
9952 agency="Azerbaijan"
0-1,20-39,400-799,8000-9999
9953 agency="Lebanon"
0-0,10-39,400-599,60-89,9000-9999
9954 agency="Morocco"
0-1,20-39,400-799,8000-9999
9955 agency="Lithuania"
00-39,400-929,9300-9999
9956 agency="Cameroon"
0-0,10-39,400-899,9000-9999
9957 agency="Jordan"
00-39,400-649,65-69,70-84,8500-8799,88-99
9958 agency="Bosnia and Herzegovina"
00-01,020-029,0300-0399,040-089,0900-0999,10-18,1900-1999,20-49,500-899
9000-9999
9959 agency="Libya"
0-1,20-79,800-949,9500-9699,970-979,98-99
9960 agency="Saudi Arabia"
00-59,600-899,9000-9999
9961 agency="Algeria"
0-2,30-69,700-949,9500-9999
9962 agency="Panama"
00-54,5500-5599,56-59,600-849,8500-9999
9963 agency="Cyprus"
0-1,2000-2499,250-279,2800-2999,30-54,550-734,7350-7499,7500-9999
9964 agency="Ghana"
0-6,70-94,950-999
9965 agency="Kazakhstan"
00-39,400-899,9000-9999
9966 agency="Kenya"
000-149,1500-1999,20-69,7000-7499,750-959,9600-9999
9967 agency="Kyrgyz Republic"
00-39,400-899,9000-9999
9968 agency="Costa Rica"
00-49,500-939,9400-9999
9970 agency="Uganda"
00-39,400-899,9000-9999
9971 agency="Singapore"
0-5,60-89,900-989,9900-9999
9972 agency="Peru"
00-09,1-1,200-249,2500-2999,30-59,600-899,9000-9999
9973 agency="Tunisia"
00-05,060-089,0900-0999,10-69,700-969,9700-9999
9974 agency="Uruguay"
0-2,30-54,550-749,7500-9099,91-94,95-99
9975 agency="Moldova"
0-0,100-299,3000-3999,4000-4499,45-89,900-949,9500-9999
9976 agency="Tanzania"
0-5,60-89,900-989,9900-9999
9977 agency="Costa Rica"
00-89,900-989,9900-9999
9978 agency="Ecuador"
00-29,300-399,40-94,950-989,9900-9999
9979 agency="Iceland"
0-4,50-64,650-659,66-75,760-899,9000-9999
9980 agency="Papua New Guinea"
0-3,40-89,900-989,9900-9999
9981 agency="Morocco"
00-09,100-159,1600-1999,20-79,800-949,9500-9999
9982 agency="Zambia"
00-79,800-989,9900-9999
9983 agency="Gambia"
80-94,950-989,9900-9999
9984 agency="Latvia"
00-49,500-899,9000-9999
9985 agency="Estonia"
0-4,50-79,800-899,9000-9999
9986 agency="Lithuania"
00-39,400-899,9000-9399,940-969,97-99
9987 agency="Tanzania"
00-39,400-879,8800-9999
9988 agency="Ghana"
0-2,30-54,550-749,7500-9999
9989 agency="Macedonia"
0-0,100-199,2000-2999,30-59,600-949,9500-9999
99901 agency="Bahrain"
00-49,500-799,80-99
99902 agency="Reserved Agency"
99903 agency="Mauritius"
0-1,20-89,900-999
99904 agency="Curaçao"
0-5,60-89,900-999
99905 agency="Bolivia"
0-3,40-79,800-999
99906 agency="Kuwait"
0-2,30-59,600-699,70-89,90-94,950-999
99908 agency="Malawi"
0-0,10-89,900-999
99909 agency="Malta"
0-3,40-94,950-999
99910 agency="Sierra Leone"
0-2,30-89,900-999
99911 agency="Lesotho"
00-59,600-999
99912 agency="Botswana"
0-3,400-599,60-89,900-999
99913 agency="Andorra"
0-2,30-35,600-604
99914 agency="Suriname"
0-4,50-89,900-999
99915 agency="Maldives"
0-4,50-79,800-999
99916 agency="Namibia"
0-2,30-69,700-999
99917 agency="Brunei Darussalam"
0-2,30-89,900-999
99918 agency="Faroe Islands"
0-3,40-79,800-999
99919 agency="Benin"
0-2,300-399,40-69,70-79,800-849,850-899,900-999
99920 agency="Andorra"
0-4,50-89,900-999
99921 agency="Qatar"
0-1,20-69,700-799,8-8,90-99
99922 agency="Guatemala"
0-3,40-69,700-999
99923 agency="El Salvador"
0-1,20-79,800-999
99924 agency="Nicaragua"
0-1,20-79,800-999
99925 agency="Paraguay"
0-3,40-79,800-999
99926 agency="Honduras"
0-0,10-59,600-869,87-89,90-99
99927 agency="Albania"
0-2,30-59,600-999
99928 agency="Georgia"
0-0,10-79,800-999
99929 agency="Mongolia"
0-4,50-79,800-999
99930 agency="Armenia"
0-4,50-79,800-999
99931 agency="Seychelles"
0-4,50-79,800-999
99932 agency="Malta"
0-0,10-59,600-699,7-7,80-99
99933 agency="Nepal"
0-2,30-59,600-999
99934 agency="Dominican Republic"
0-1,20-79,800-999
99935 agency="Haiti"
0-2,30-59,600-699,7-8,90-99
99936 agency="Bhutan"
0-0,10-59,600-999
99937 agency="Macau"
0-1,20-59,600-999
99938 agency="Srpska, Republic of"
0-1,20-59,600-899,90-99
99939 agency="Guatemala"
0-5,60-89,900-999
99940 agency="Georgia"
0-0,10-69,700-999
99941 agency="Armenia"
0-2,30-79,800-999
99942 agency="Sudan"
0-4,50-79,800-999
99943 agency="Albania"
0-2,30-59,600-999
99944 agency="Ethiopia"
0-4,50-79,800-999
99945 agency="Namibia"
0-5,60-89,900-999
99946 agency="Nepal"
0-2,30-59,600-999
99947 agency="Tajikistan"
0-2,30-69,700-999
99948 agency="Eritrea"
0-4,50-79,800-999
99949 agency="Mauritius"
0-1,20-89,900-999
99950 agency="Cambodia"
0-4,50-79,800-999
99951 agency="Reserved Agency"
99952 agency="Mali"
0-4,50-79,800-999
99953 agency="Paraguay"
0-2,30-79,800-939,94-99
99954 agency="Bolivia"
0-2,30-69,700-879,88-99
99955 agency="Srpska, Republic of"
0-1,20-59,600-799,80-99
99956 agency="Albania"
00-59,600-859,86-99
99957 agency="Malta"
0-1,20-79,800-999
99958 agency="Bahrain"
0-4,50-93,940-949,950-999
99959 agency="Luxembourg"
0-2,30-59,600-999
99960 agency="Malawi"
0-0,10-94,950-999
99961 agency="El Salvador"
0-3,40-89,900-999
99962 agency="Mongolia"
0-4,50-79,800-999
99963 agency="Cambodia"
00-49,500-919,92-99
99964 agency="Nicaragua"
0-1,20-79,800-999
99965 agency="Macau"
0-3,40-62,630-999
99966 agency="Kuwait"
0-2,30-69,700-799,80-94
99967 agency="Paraguay"
0-1,20-59,600-899
99968 agency="Botswana"
0-3,400-599,60-89,900-999
99969 agency="Oman"
0-4,50-79,800-999
99970 agency="Haiti"
0-4,50-89,900-999
99971 agency="Myanmar"
0-5,60-84,850-999
99972 agency="Faroe Islands"
0-4,50-89,900-999
99973 agency="Mongolia"
0-3,40-79,800-999
99974 agency="Bolivia"
40-79,800-999
99975 agency="Tajikistan"
0-3,40-79,800-999
99976 agency="Srpska, Republic of"
0-1,20-59,600-799
99977 agency="Rwanda"
0-1,40-69,700-799
979
10-12
10 agency="France"
00-19,200-699,7000-8999,90000-97599,976000-999999
11 agency="Korea, Republic"
00-24,250-549,5500-8499,85000-94999,950000-999999
12 agency="Italy"
200-200

View file

@ -0,0 +1,187 @@
# isbn.py - functions for handling ISBNs
#
# Copyright (C) 2010, 2011, 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
# 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
"""ISBN (International Standard Book Number).
The ISBN is the International Standard Book Number, used to identify
publications. This module supports both numbers in ISBN-10 (10-digit) and
ISBN-13 (13-digit) format.
>>> validate('978-9024538270')
'9789024538270'
>>> validate('978-9024538271')
Traceback (most recent call last):
...
InvalidChecksum: ...
>>> compact('1-85798-218-5')
'1857982185'
>>> format('9780471117094')
'978-0-471-11709-4'
>>> format('1857982185')
'1-85798-218-5'
>>> isbn_type('1-85798-218-5')
'ISBN10'
>>> isbn_type('978-0-471-11709-4')
'ISBN13'
>>> to_isbn13('1-85798-218-5')
'978-1-85798-218-3'
>>> to_isbn10('978-1-85798-218-3')
'1-85798-218-5'
"""
from stdnum import ean
from stdnum.exceptions import *
from stdnum.util import clean
def compact(number, convert=False):
"""Convert the ISBN to the minimal representation. This strips the number
of any valid ISBN separators and removes surrounding whitespace. If the
covert parameter is True the number is also converted to ISBN-13
format."""
number = clean(number, ' -').strip().upper()
if len(number) == 9:
number = '0' + number
if convert:
return to_isbn13(number)
return number
def _calc_isbn10_check_digit(number):
"""Calculate the ISBN check digit for 10-digit numbers. The number passed
should not have the check bit included."""
check = sum((i + 1) * int(n)
for i, n in enumerate(number)) % 11
return 'X' if check == 10 else str(check)
def validate(number, convert=False):
"""Checks to see if the number provided is a valid ISBN (either a legacy
10-digit one or a 13-digit one). This checks the length and the check
bit but does not check if the group and publisher are valid (use split()
for that)."""
number = compact(number, convert=False)
if not number[:-1].isdigit():
raise InvalidFormat()
if len(number) == 10:
if _calc_isbn10_check_digit(number[:-1]) != number[-1]:
raise InvalidChecksum()
elif len(number) == 13:
ean.validate(number)
else:
raise InvalidLength()
if convert:
number = to_isbn13(number)
return number
def isbn_type(number):
"""Check the passed number and returns 'ISBN13', 'ISBN10' or None (for
invalid) for checking the type of number passed."""
try:
number = validate(number, convert=False)
except ValidationError:
return None
if len(number) == 10:
return 'ISBN10'
else: # len(number) == 13:
return 'ISBN13'
def is_valid(number):
"""Checks to see if the number provided is a valid ISBN (either a legacy
10-digit one or a 13-digit one). This checks the length and the check
bit but does not check if the group and publisher are valid (use split()
for that)."""
try:
return bool(validate(number))
except ValidationError:
return False
def to_isbn13(number):
"""Convert the number to ISBN-13 format."""
number = number.strip()
min_number = compact(number, convert=False)
if len(min_number) == 13:
return number # nothing to do, already ISBN-13
# put new check digit in place
number = number[:-1] + ean.calc_check_digit('978' + min_number[:-1])
# add prefix
if ' ' in number:
return '978 ' + number
elif '-' in number:
return '978-' + number
else:
return '978' + number
def to_isbn10(number):
"""Convert the number to ISBN-10 format."""
number = number.strip()
min_number = compact(number, convert=False)
if len(min_number) == 10:
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'):
raise InvalidFormat('Does not use 978 Bookland prefix.')
# strip EAN prefix
number = number[3:-1].strip().strip('-')
digit = _calc_isbn10_check_digit(min_number[3:-1])
# append the new check digit
if ' ' in number:
return number + ' ' + digit
elif '-' in number:
return number + '-' + digit
else:
return number + digit
def split(number, convert=False):
"""Split the specified ISBN into an EAN.UCC prefix, a group prefix, a
registrant, an item number and a check-digit. If the number is in ISBN-10
format the returned EAN.UCC prefix is '978'. If the covert parameter is
True the number is converted to ISBN-13 format first."""
from stdnum import numdb
# clean up number
number = compact(number, convert)
# get Bookland prefix if any
delprefix = False
if len(number) == 10:
number = '978' + number
delprefix = True
# split the number
result = numdb.get('isbn').split(number[:-1])
itemnr = result.pop() if result else ''
prefix = result.pop(0) if result else ''
group = result.pop(0) if result else ''
publisher = result.pop(0) if result else ''
# return results
return ('' if delprefix else prefix, group, publisher, itemnr, number[-1])
def format(number, separator='-', convert=False):
"""Reformat the passed number to the standard format with the EAN.UCC
prefix (if any), the group prefix, the registrant, the item number and
the check-digit separated (if possible) by the specified separator.
Passing an empty separator should equal compact() though this is less
efficient. If the covert parameter is True the number is converted to
ISBN-13 format first."""
return separator.join(x for x in split(number, convert) if x)

View file

@ -0,0 +1,34 @@
# generated from ISIL Registration Authority, downloaded from
# http://biblstandard.dk/isil/
US$ country="United States of America" ra_url="http://www.loc.gov/marc/organizations/" ra="Library of Congress"
AR$ country="Argentine Republic" ra_url="http://www.iram.org.ar" ra="Argentine Standardization and Certification Institute (IRAM)"
AT$ country="Austria" ra_url="http://www.obvsg.at" ra="Die Österreichische Bibliothekenverbund und Service GmbH"
AU$ country="Australia" ra_url="http://www.nla.gov.au/ilrs" ra="National Library of Australia"
BE$ country="Belgium" ra_url="http://www.kbr.be" ra="Royal Library of Belgium"
BY$ country="Belarus" ra_url="http://www.nlb.by/portal/page/portal/index?lang=en" ra="National Library of Belarus"
CA$ country="Canada" ra_url="http://www.collectionscanada.ca/ill/s16-206-e.html#3.2.2" ra="Library and Archives Canada"
CH$ country="Switzerland" ra_url="http://www.nb.admin.ch/slb/slb_professionnel/01540/index.html?lang=en" ra="Swiss National Library"
CY$ country="Cyprus" ra_url="http://library.cut.ac.cy/en/isil" ra="Cyprus University of Technology Library"
DE$ country="Germany" ra_url="http://sigel.staatsbibliothek-berlin.de/" ra="Staatsbibliothek zu Berlin"
DK$ country="Denmark" ra_url="http://www.kulturstyrelsen.dk/english/institutions/libraries/national-solutions/standards/danish-library-number/" ra="Danish Agency for Culture"
EG$ country="Egypt" ra_url="http://www.sti.sci.eg/index.php?option=com_content&view=article&id=30:focal-point&catid=1:pages&Itemid=56" ra="Egyptian National Scientific and Technical Information Network (ENSTINET)"
FI$ country="Finland" ra_url="http://www.nationallibrary.fi/libraries/standards/isil.html" ra="The National Library of Finland"
FR$ country="France" ra_url="http://www.abes.fr" ra="Agence Bibliographique de l'Enseignement Superieur"
GB$ country="United Kingdom" ra_url="http://www.bl.uk/bibliographic/isilagency.html" ra="British Library"
GL$ country="Greenland" ra_url="http://www.katak.gl/ISIL/Greenlandic_library_identifiers.html" ra="Central and Public Library of Greenland"
IL$ country="Israel" ra_url="http://nli.org.il/eng" ra="National Library of Israel"
IR$ country="Islamic Republic of Iran" ra_url="http://www.nlai.ir/special_services/stds/isil.htm" ra="National Library and Archives of Islamic Republic of Iran of Iran"
IT$ country="Italy" ra_url="http://www.iccu.sbn.it/genera.jsp?id=78&l=en" ra="Istituto Centrale per il Catalogo Unico delle biblioteche italiane e per le informazioni bibliografiche"
JP$ country="Japan" ra_url="http://www.ndl.go.jp/en/library/isil/index.html" ra="National Diet Library"
KR$ country="Republic of Korea" ra_url="http://www.nl.go.kr/isil/" ra="The National Library of Korea"
LU$ country="Luxembourg" ra_url="http://www.anlux.lu" ra="Archives nationales de Luxembourg"
NL$ country="The Netherlands" ra_url="http://www.kb.nl/expertise/voor-bibliotheken/interbibliotheciar-leenverkeer/internationale-standard-identifier-for-libraries-isil" ra="Koninklijke Bibliotheek, National Library of the Netherlands"
NO$ country="Norway" ra_url="http://www.nb.no/" ra="National Library of Norway"
NZ$ country="New Zealand" ra_url="http://natlib.govt.nz/" ra="National Library of New Zealand Te Puna Matauranga o Aotearoa"
QA$ country="Qatar" ra_url="http://www.qnl.qa/" ra="Qatar National Library (QNL)"
RU$ country="Russian Federation" ra_url="http://english.gpntb.ru/" ra="Russian National Public Library for Science and Technology"
SI$ country="The Republic of Slovenia" ra_url="http://www.nuk.uni-lj.si/nukeng3.asp?id=311364382" ra="National and University Library"
SK$ country="Slovak Republic" ra_url="http://www.snk.sk" ra="Slovak National Library"
O$ ra="See OCLC"
OCLC$ country="WorldCat Symbol" ra_url="http://www.oclc.org" ra="OCLC"
ZDB$ country="Staatsbibliothek zu Berlin - Zeitschriftendatenbank" ra="Staatsbibliothek zu Berlin"

View file

@ -0,0 +1,96 @@
# isil.py - functions for handling identifiers for libraries and related
# organizations
#
# Copyright (C) 2011, 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
# 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
"""ISIL (International Standard Identifier for Libraries).
The ISIL is the International Standard Identifier for
Libraries and Related Organizations.
>>> validate('IT-RM0267')
'IT-RM0267'
>>> validate('OCLC-DLC')
'OCLC-DLC'
>>> validate('WW-RM0267') # unregistered country code
Traceback (most recent call last):
...
InvalidComponent: ...
>>> validate('WW-RM026712423345334534512334534545') # too long
Traceback (most recent call last):
...
InvalidLength: ...
>>> format('it-RM0267')
'IT-RM0267'
>>> format('zz-RM0267') # unknown agencies are left alone
'zz-RM0267'
"""
from stdnum.exceptions import *
from stdnum.util import clean
# the valid characters in an ISIL
_alphabet = set('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-:/')
def compact(number):
"""Convert the ISIL to the minimal representation. This strips
surrounding whitespace."""
return clean(number, '').strip()
def _known_agency(agency):
"""Checks whether the specified agency is valid."""
# look it up in the db
from stdnum import numdb
results = numdb.get('isil').info(agency.upper() + '$')
# there should be only one part and it should have properties
return len(results) == 1 and bool(results[0][1])
def validate(number):
"""Checks to see if the number provided is a valid isil (or isilSV)
number."""
number = compact(number)
for n in number:
if n not in _alphabet:
raise InvalidFormat()
if len(number) > 15:
raise InvalidLength()
if not _known_agency(number.split('-')[0]):
raise InvalidComponent()
return number
def is_valid(number):
"""Checks to see if the number provided is a valid isil (or isilSV)
number."""
try:
return bool(validate(number))
except ValidationError:
return False
def format(number):
"""Reformat the passed number to the standard format."""
number = compact(number)
parts = number.split('-')
if len(parts) > 1 and _known_agency(parts[0]):
parts[0] = parts[0].upper()
return '-'.join(parts)

View file

@ -0,0 +1,125 @@
# isin.py - functions for handling ISIN numbers
#
# 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
"""ISIN (International Securities Identification Number).
The ISIN is a 12-character alpha-numerical code specified in ISO 6166 used to
identify exchange listed securities such as bonds, commercial paper, stocks
and warrants. The number is formed of a two-letter country code, a nine
character national security identifier and a single check digit.
This module does not currently separately validate the embedded national
security identifier part (e.g. when it is a CUSIP).
More information:
https://en.wikipedia.org/wiki/International_Securities_Identification_Number
>>> validate('US0378331005')
'US0378331005'
>>> validate('US0378331003')
Traceback (most recent call last):
...
InvalidChecksum: ...
>>> from_natid('gb', 'BYXJL75')
'GB00BYXJL758'
"""
from stdnum.exceptions import *
from stdnum.util import clean
# all valid ISO 3166-1 alpha-2 country codes
_iso_3116_1_country_codes = [
'AD', 'AE', 'AF', 'AG', 'AI', 'AL', 'AM', 'AO', 'AQ', 'AR', 'AS', 'AT',
'AU', 'AW', 'AX', 'AZ', 'BA', 'BB', 'BD', 'BE', 'BF', 'BG', 'BH', 'BI',
'BJ', 'BL', 'BM', 'BN', 'BO', 'BQ', 'BR', 'BS', 'BT', 'BV', 'BW', 'BY',
'BZ', 'CA', 'CC', 'CD', 'CF', 'CG', 'CH', 'CI', 'CK', 'CL', 'CM', 'CN',
'CO', 'CR', 'CU', 'CV', 'CW', 'CX', 'CY', 'CZ', 'DE', 'DJ', 'DK', 'DM',
'DO', 'DZ', 'EC', 'EE', 'EG', 'EH', 'ER', 'ES', 'ET', 'FI', 'FJ', 'FK',
'FM', 'FO', 'FR', 'GA', 'GB', 'GD', 'GE', 'GF', 'GG', 'GH', 'GI', 'GL',
'GM', 'GN', 'GP', 'GQ', 'GR', 'GS', 'GT', 'GU', 'GW', 'GY', 'HK', 'HM',
'HN', 'HR', 'HT', 'HU', 'ID', 'IE', 'IL', 'IM', 'IN', 'IO', 'IQ', 'IR',
'IS', 'IT', 'JE', 'JM', 'JO', 'JP', 'KE', 'KG', 'KH', 'KI', 'KM', 'KN',
'KP', 'KR', 'KW', 'KY', 'KZ', 'LA', 'LB', 'LC', 'LI', 'LK', 'LR', 'LS',
'LT', 'LU', 'LV', 'LY', 'MA', 'MC', 'MD', 'ME', 'MF', 'MG', 'MH', 'MK',
'ML', 'MM', 'MN', 'MO', 'MP', 'MQ', 'MR', 'MS', 'MT', 'MU', 'MV', 'MW',
'MX', 'MY', 'MZ', 'NA', 'NC', 'NE', 'NF', 'NG', 'NI', 'NL', 'NO', 'NP',
'NR', 'NU', 'NZ', 'OM', 'PA', 'PE', 'PF', 'PG', 'PH', 'PK', 'PL', 'PM',
'PN', 'PR', 'PS', 'PT', 'PW', 'PY', 'QA', 'RE', 'RO', 'RS', 'RU', 'RW',
'SA', 'SB', 'SC', 'SD', 'SE', 'SG', 'SH', 'SI', 'SJ', 'SK', 'SL', 'SM',
'SN', 'SO', 'SR', 'SS', 'ST', 'SV', 'SX', 'SY', 'SZ', 'TC', 'TD', 'TF',
'TG', 'TH', 'TJ', 'TK', 'TL', 'TM', 'TN', 'TO', 'TR', 'TT', 'TV', 'TW',
'TZ', 'UA', 'UG', 'UM', 'US', 'UY', 'UZ', 'VA', 'VC', 'VE', 'VG', 'VI',
'VN', 'VU', 'WF', 'WS', 'YE', 'YT', 'ZA', 'ZM', 'ZW']
# the special XS country code is for international securities
# substitute agencies can allocate an ISIN starting with XA (CUSIP Global
# Services), XB (NSD Russia), XC (WM Datenservice Germany) or XD (SIX
# Telekurs).
_country_codes = set(_iso_3116_1_country_codes + [
'XS', 'EU', 'XA', 'XB', 'XC', 'XD'])
# the letters allowed in an ISIN
_alphabet = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
def compact(number):
"""Convert the number to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace."""
return clean(number, ' ').strip().upper()
def calc_check_digit(number):
"""Calculate the check digits for the number."""
# convert to numeric first, then double some, then sum individual digits
number = ''.join(str(_alphabet.index(n)) for n in number)
number = ''.join(
str(int(n) * (2 - i % 2)) for i, n in enumerate(reversed(number)))
return str((10 - sum(int(n) for n in number)) % 10)
def validate(number):
"""Checks to see if the number provided is valid. This checks the length
and check digit."""
number = compact(number)
if not all(x in _alphabet for x in number):
raise InvalidFormat()
if len(number) != 12:
raise InvalidLength()
if number[:2] not in _country_codes:
raise InvalidComponent()
if calc_check_digit(number[:-1]) != number[-1]:
raise InvalidChecksum()
return number
def is_valid(number):
"""Checks to see if the number provided is valid. This checks the length
and check digit."""
try:
return bool(validate(number))
except ValidationError:
return False
def from_natid(country_code, number):
"""Generate an ISIN from a national security identifier."""
number = compact(number)
number = country_code.upper() + (9 - len(number)) * '0' + number
return number + calc_check_digit(number)

View file

@ -0,0 +1,132 @@
# ismn.py - functions for handling ISMNs
#
# Copyright (C) 2010, 2011, 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
# 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
"""ISMN (International Standard Music Number).
The ISMN (International Standard Music Number) is used to identify sheet
music. This module handles both numbers in the 10-digit 13-digit format.
>>> validate('979-0-3452-4680-5')
'9790345246805'
>>> validate('9790060115615')
'9790060115615'
>>> ismn_type(' M-2306-7118-7')
'ISMN10'
>>> validate('9790060115614')
Traceback (most recent call last):
...
InvalidChecksum: ...
>>> compact(' 979-0-3452-4680-5')
'9790345246805'
>>> format('9790060115615')
'979-0-060-11561-5'
>>> format('M230671187')
'979-0-2306-7118-7'
>>> to_ismn13('M230671187')
'9790230671187'
"""
from stdnum import ean
from stdnum.exceptions import *
from stdnum.util import clean
def compact(number):
"""Convert the ISMN to the minimal representation. This strips the number
of any valid ISMN separators and removes surrounding whitespace."""
return clean(number, ' -.').strip().upper()
def validate(number):
"""Checks to see if the number provided is a valid ISMN (either a legacy
10-digit one or a 13-digit one). This checks the length and the check
bit but does not check if the publisher is known."""
number = compact(number)
if len(number) == 10:
if number[0] != 'M':
raise InvalidFormat()
ean.validate('9790' + number[1:])
else:
ean.validate(number)
return number
def ismn_type(number):
"""Check the type of ISMN number passed and return 'ISMN13', 'ISMN10'
or None (for invalid)."""
try:
number = validate(number)
except ValidationError:
return None
if len(number) == 10:
return 'ISMN10'
else: # len(number) == 13:
return 'ISMN13'
def is_valid(number):
"""Checks to see if the number provided is a valid ISMN (either a legacy
10-digit one or a 13-digit one). This checks the length and the check
bit but does not check if the publisher is known."""
try:
return bool(validate(number))
except ValidationError:
return False
def to_ismn13(number):
"""Convert the number to ISMN13 (EAN) format."""
number = number.strip()
min_number = compact(number)
if len(min_number) == 13:
return number # nothing to do, already 13 digit format
# add prefix and strip the M
if ' ' in number:
return '979 0' + number[1:]
elif '-' in number:
return '979-0' + number[1:]
else:
return '9790' + number[1:]
# these are the ranges allocated to publisher codes
_ranges = (
(3, '000', '099'), (4, '1000', '3999'), (5, '40000', '69999'),
(6, '700000', '899999'), (7, '9000000', '9999999'))
def split(number):
"""Split the specified ISMN into a bookland prefix (979), an ISMN
prefix (0), a publisher element (3 to 7 digits), an item element (2 to
6 digits) and a check digit."""
# clean up number
number = to_ismn13(compact(number))
# rind the correct range and split the number
for length, low, high in _ranges:
if low <= number[4:4 + length] <= high:
return (number[:3], number[3], number[4:4 + length],
number[4 + length:-1], number[-1])
def format(number, separator='-'):
"""Reformat the passed number to the standard format with the
prefixes, the publisher element, the item element and the check-digit
separated by the specified separator. The number is converted to the
13-digit format silently."""
return separator.join(x for x in split(number) if x)

View file

@ -0,0 +1,83 @@
# iso6346.py - functions for handling ISO 6346
#
# Copyright (C) 2014 Openlabs Technologies & Consulting (P) Limited
# Copyright (C) 2014 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
"""ISO 6346 (International standard for container identification)
ISO 6346 is an international standard covering the coding, identification and
marking of intermodal (shipping) containers used within containerized
intermodal freight transport. The standard establishes a visual identification
system for every container that includes a unique serial number (with check
digit), the owner, a country code, a size, type and equipment category as well
as any operational marks. The standard is managed by the International
Container Bureau (BIC).
>>> validate('csqu3054383')
'CSQU3054383'
>>> validate('CSQU3054384')
Traceback (most recent call last):
...
InvalidChecksum: ...
"""
import re
from stdnum.exceptions import InvalidChecksum, InvalidFormat, InvalidLength, \
ValidationError
from stdnum.util import clean
_iso6346_re = re.compile(r'^\w{3}(U|J|Z|R)\d{7}$')
def compact(number):
"""Convert the number to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace."""
return clean(number).strip().upper()
def calc_check_digit(number):
"""Calculate check digit and return it for the 10 digit owner code and
serial number."""
number = compact(number)
alphabet = '0123456789A BCDEFGHIJK LMNOPQRSTU VWXYZ'
return str(sum(
alphabet.index(n) * pow(2, i)
for i, n in enumerate(number)) % 11)
def validate(number):
"""Validate the given number (unicode) for conformity to ISO 6346."""
number = compact(number)
if len(number) != 11:
raise InvalidLength()
if not _iso6346_re.match(number):
raise InvalidFormat()
if calc_check_digit(number[:-1]) != number[-1]:
raise InvalidChecksum()
return number
def is_valid(number):
"""Check whether the number conforms to the standard ISO6346. Unlike
the validate function, this will not raise ValidationError(s)."""
try:
return bool(validate(number))
except ValidationError:
return False

View file

@ -0,0 +1,30 @@
# __init__.py - functions for performing the ISO 7064 algorithms
#
# Copyright (C) 2010, 2012 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 the ISO 7064 algorithms.
This package provides a number of modules for calculation and verification
of numbers using one of the ISO 7064 algorithms.
Note that these functions were not implemented using the ISO text itself
because the text is not available for free. These functions were
implemented based on information on the algorithms found online and some
reverse engineering. If anyone can provide a legal copy of the ISO/IEC
7064 standard these functions can be validated and perhaps improved.
"""

View file

@ -0,0 +1,71 @@
# mod_11_10.py - functions for performing the ISO 7064 Mod 11, 10 algorithm
#
# Copyright (C) 2010, 2011, 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
# 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
"""The ISO 7064 Mod 11, 10 algorithm.
The Mod 11, 10 algorithm uses a number of calculations modulo 11 and 10 to
determine a checksum.
For a module that can do generic Mod x+1, x calculations see the
:mod:`stdnum.iso7064.mod_37_36` module.
>>> calc_check_digit('79462')
'3'
>>> validate('794623')
'794623'
>>> calc_check_digit('00200667308')
'5'
>>> validate('002006673085')
'002006673085'
"""
from stdnum.exceptions import *
def checksum(number):
"""Calculate the checksum. A valid number should have a checksum of 1."""
check = 5
for n in number:
check = (((check or 10) * 2) % 11 + int(n)) % 10
return check
def calc_check_digit(number):
"""With the provided number, calculate the extra digit that should be
appended to make it a valid number."""
return str((1 - ((checksum(number) or 10) * 2) % 11) % 10)
def validate(number):
"""Checks whether the check digit is valid."""
try:
valid = checksum(number) == 1
except Exception:
raise InvalidFormat()
if not valid:
raise InvalidChecksum()
return number
def is_valid(number):
"""Checks whether the check digit is valid."""
try:
return bool(validate(number))
except ValidationError:
return False

View file

@ -0,0 +1,74 @@
# mod_11_2.py - functions for performing the ISO 7064 Mod 11, 2 algorithm
#
# Copyright (C) 2010, 2011, 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
# 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
"""The ISO 7064 Mod 11, 2 algorithm.
The Mod 11, 2 algorithm is a simple module 11 checksum where the check
digit can be an X to make the number valid.
For a module that can do generic Mod x, 2 calculations see the
:mod:`stdnum.iso7064.mod_37_2` module.
>>> calc_check_digit('0794')
'0'
>>> validate('07940')
'07940'
>>> calc_check_digit('079')
'X'
>>> validate('079X')
'079X'
>>> checksum('079X')
1
"""
from stdnum.exceptions import *
def checksum(number):
"""Calculate the checksum. A valid number should have a checksum of 1."""
check = 0
for n in number:
check = (2 * check + int(10 if n == 'X' else n)) % 11
return check
def calc_check_digit(number):
"""With the provided number, calculate the extra digit that should be
appended to make it a valid number."""
c = (1 - 2 * checksum(number)) % 11
return 'X' if c == 10 else str(c)
def validate(number):
"""Checks whether the check digit is valid."""
try:
valid = checksum(number) == 1
except Exception:
raise InvalidFormat()
if not valid:
raise InvalidChecksum()
return number
def is_valid(number):
"""Checks whether the check digit is valid."""
try:
return bool(validate(number))
except ValidationError:
return False

Some files were not shown because too many files have changed in this diff Show more