Source code for checkdigit.luhn

# /usr/bin/env python

# This file is part of checkdigit.

# checkdigit is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# checkdigit 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 General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with checkdigit.  If not, see <http://www.gnu.org/licenses/>.

"""Luhn Validation Functions.

The luhn algorithm has a variety of applications, including in credit cards and IMEI numbers.

"""

from checkdigit._data import cleanse, missing_template


[docs]def calculate(data: str) -> str: """Calculates the luhn check digit. Args: data: A block of data without the check digit Returns: str: A string representing the missing check digit Examples: >>> from checkdigit import luhn >>> luhn.calculate("53251309870224") '3' >>> luhn.calculate("950123440000") '8' """ data = cleanse(data) # Double every other digit, starting from the final digit backwards # i.e. double 0th digit, 2nd, 4th, ... double_digits = ( int(element) if index % 2 else int(element) * 2 for index, element in enumerate(data[::-1]) ) # For digits with more than one digit, sum the digits together # The maximum is 9*2 = 18. This divmod method will work <100 sum_digits = sum(sum(divmod(i, 10)) for i in double_digits) # Mod 10 returns 0-9 (not 10 or 11) # Hence convert method not required (faster to use str) return str((sum_digits * 9) % 10)
[docs]def validate(data: str) -> bool: """Validates a luhn check digit. Args: data: A string of characters representing a full luhn code Returns: bool: A boolean representing whether the check digit validates the data or not Examples: >>> from checkdigit import luhn >>> luhn.validate("541756116585277") True >>> luhn.validate("79927398713") True >>> luhn.validate("49927398717") False >>> luhn.validate("1234567812345678") False """ data = cleanse(data) return ( calculate(data[:-1]) == data[-1] ) # Determines if calculated Check Digit of the data is the last digit given
[docs]def missing(data: str) -> str: """Calculates a missing digit in a luhn code. Args: data: A string of characters representing a full luhn code with a question mark for a missing character Returns: str: The missing value that should've been where the question mark was Examples: >>> from checkdigit import luhn >>> luhn.missing("54175611658527?") '7' >>> luhn.missing("515853022?76176") '1' >>> luhn.missing("78369216316") 'Invalid' """ return missing_template(data, "luhn")