<commit_before># iban.py - functions for handling International Bank Account Numbers (IBANs)
#
# Copyright (C) 2011 <NAME>
#
# 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

"""Module for handling IBANs (International Bank Account Numbers)
numbers, used to identify bank accounts across national borders.


>>> is_valid('GR16 0110 1050 0000 1054 7023 795')
True
>>> is_valid('BE31435411161155')
True
>>> compact('GR16 0110 1050 0000 1054 7023 795')
'GR1601101050000010547023795'
>>> format('GR1601101050000010547023795')
'GR16 0110 1050 0000 1054 7023 795'
"""

from stdnum import numdb
from stdnum.iso7064 import mod_97_10
import re


# our open copy of the IBAN database
_ibandb = numdb.get('iban')

def compact(number):
    """Convert the iban number to the minimal representation. This strips the
    number of any valid separators and removes surrounding whitespace."""
    return number.replace(' ','').replace('-','').strip().upper()

_alphabet = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'

def _convert(number):
    """Prepare the number to it's 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])

# regular expression to check IBAN structure
_struct_re = re.compile('([1-9][0-9]*)!([nac])')

def _matches_structure(number, structure):
    """Check the supplied number against the supplied structure."""
    start = 0
    for length, code in _struct_re.findall(structure):
        length = int(length)
        if code == 'n' and not number[start:start + length].isdigit():
            return False
        elif code == 'a' and not number[start:start + length].isalpha():
            return False
        elif code == 'c' and not number[start:start + length].isalnum():
            return False # should not happen due to checksum check
        start += length
    # the whole number should be parsed now
    return start == len(number)

def is_valid(number):
    """Checks to see if the number provided is a valid IBAN."""
    try:
        number = compact(number)
    except:
        return False
    # ensure that checksum is valid
    if not mod_97_10.is_valid(_convert(number)):
        return False
    # look up the number
    info = _ibandb.info(number)
    # check if the number has the correct structure
    return _matches_structure(number[4:], info[0][1].get('bban', ''))

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))
<commit_msg>move more validation into try/except (specifically the _convert() call)<commit_after># iban.py - functions for handling International Bank Account Numbers (IBANs)
#
# Copyright (C) 2011 <NAME>
#
# 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

"""Module for handling IBANs (International Bank Account Numbers)
numbers, used to identify bank accounts across national borders.


>>> is_valid('GR16 0110 1050 0000 1054 7023 795')
True
>>> is_valid('BE31435411161155')
True
>>> compact('GR16 0110 1050 0000 1054 7023 795')
'GR1601101050000010547023795'
>>> format('GR1601101050000010547023795')
'GR16 0110 1050 0000 1054 7023 795'
"""

from stdnum import numdb
from stdnum.iso7064 import mod_97_10
import re


# our open copy of the IBAN database
_ibandb = numdb.get('iban')

def compact(number):
    """Convert the iban number to the minimal representation. This strips the
    number of any valid separators and removes surrounding whitespace."""
    return number.replace(' ','').replace('-','').strip().upper()

_alphabet = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'

def _convert(number):
    """Prepare the number to it's 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])

# regular expression to check IBAN structure
_struct_re = re.compile('([1-9][0-9]*)!([nac])')

def _matches_structure(number, structure):
    """Check the supplied number against the supplied structure."""
    start = 0
    for length, code in _struct_re.findall(structure):
        length = int(length)
        if code == 'n' and not number[start:start + length].isdigit():
            return False
        elif code == 'a' and not number[start:start + length].isalpha():
            return False
        elif code == 'c' and not number[start:start + length].isalnum():
            return False # should not happen due to checksum check
        start += length
    # the whole number should be parsed now
    return start == len(number)

def is_valid(number):
    """Checks to see if the number provided is a valid IBAN."""
    try:
        number = compact(number)
        # ensure that checksum is valid
        if not mod_97_10.is_valid(_convert(number)):
            return False
    except:
        return False
    # look up the number
    info = _ibandb.info(number)
    # check if the number has the correct structure
    return _matches_structure(number[4:], info[0][1].get('bban', ''))

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))

{'fraction_non_alphanumeric': 0.09695652173913044, 'fraction_numerical': 0.059420289855072465, 'mean_word_length': 3.8057103064066853, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7007773', 'n_tokens_mistral': 2254, 'n_tokens_neox': 1943, 'n_words': 820}