Debug an ISBN Validator - Purpose of Checking digit unclear

Tell us what’s happening:

I am struggling to understand the necessity of the “given_check_digit” variable. The way I understand it, the user inputs the length after the commit, which then is either 10 or 13. This length has nothing to do with the check digit in my opinion.
I am now at the point where I have to debug test 11 but I don’t understand why the input should be invalid.
The variable expected_check_digit = 1, so between 0-9 and the length is 10.
Why should the input be invalid?

The input test 11 test:

Your code so far


def validate_isbn(isbn, length):
    main_digits = isbn[0:length]
    given_check_digit = int(isbn[len(main_digits)+1:])

    if len(main_digits) != length:
        raise ValueError(f'ISBN-{length} code should be {length} digits long.')

    main_digits_list = [int(digit) for digit in main_digits]
    # Calculate the check digit from other digits
    if length == 10:
        expected_check_digit = calculate_check_digit_10(main_digits_list)
    else:
        expected_check_digit = calculate_check_digit_13(main_digits_list)
    # Check if the given check digit matches with the calculated check digit
    if (given_check_digit == 10 and (expected_check_digit == "X" or int(expected_check_digit) in range(10))) or (given_check_digit == 13 and int(expected_check_digit) in range(10)):
        print('Valid ISBN Code.')
    else:
        raise ValueError('Invalid ISBN Code.')

def calculate_check_digit_10(main_digits_list):
    # Note: You don't have to fully understand the logic in this function.
    digits_sum = 0
    # Multiply each of the first 9 digits by its corresponding weight (10 to 2) and sum up the results
    for index, digit in enumerate(main_digits_list):
        digits_sum += digit * (10 - index)
    # Find the remainder of dividing the sum by 11, then subtract it from 11
    result = 11 - digits_sum % 11
    # The calculation result can range from 1 to 11.
    # If the result is 11, use 0.
    # If the result is 10, use upper case X.
    # Use the value as it is for other numbers.
    if result == 11:
        expected_check_digit = '0'
    elif result == 10:
        expected_check_digit = 'X'
    else:
        expected_check_digit = str(result)
    return expected_check_digit

def calculate_check_digit_13(main_digits_list):
    # Note: You don't have to fully understand the logic in this function.
    digits_sum = 0
    # Multiply each of the first 12 digits by 1 and 3 alternately (starting with 1), and sum up the results
    for index, digit in enumerate(main_digits_list):
        if index % 2 == 0:
            digits_sum += digit * 1
        else:
            digits_sum += digit * 3
    # Find the remainder of dividing the sum by 10, then subtract it from 10
    result = 10 - digits_sum % 10
    # The calculation result can range from 1 to 10.
    # If the result is 10, use 0.
    # Use the value as it is for other numbers.
    if result == 10:
        expected_check_digit = '0'
    else:
        expected_check_digit = str(result)
    return expected_check_digit

def input_is_comma_separated(input):
    if input.count(",") == 1:
        return True
    else:
        return False

def isbn_is_digit(user_input):
    if user_input.isdigit():
        return True
    else:
        return False

def length_is_digit(length):
    if length.isdigit():
        return True
    else:
        return False

def validate_input(user_input):
    if not input_is_comma_separated(user_input):
        raise ValueError("Enter comma-separated values.")
    else:
        values = user_input.split(",")
        if not length_is_digit(values[1]):
            raise TypeError("Length must be a number.")
        elif not isbn_is_digit(values[0]):
            raise TypeError("Invalid character was found.")
        
def main():
    user_input = input('Enter ISBN and length: ')
    try:
        validate_input(user_input)
    except ValueError as e:
        print(f"{e}")
    except TypeError as e:
        print(f"{e}")
        
    values = user_input.split(",")
    isbn = values[0]
    length = int(values[1])

    try:
        validate_isbn(user_input, length)
    except ValueError as e:
        print(f"{e}")
    except TypeError as e:
        print(f"{e}")
    

#main()

Your browser information:

User Agent is: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.3.1 Safari/605.1.15

Challenge Information:

Debug an ISBN Validator - Debug an ISBN Validator

Github Link: freeCodeCamp/curriculum/challenges/english/blocks/lab-isbn-validator/686b9720ee1d032bd77a480a.md at main · freeCodeCamp/freeCodeCamp · GitHub

The input for test 11 is 1530051125,10, if you check with ISBN validators online, or calculate the check digit, the expected check digit for the 9 digits “153005112” is 6

how did you arrive to this? there may be some misunderstanding on how ISBN works

Hi there,

If the check digit can be ‘X’, does it make sense to set the given_check_digit variable to the value of the length parameter?

I also notice that you have made several significant but unnecessary changes to the validate_isbn function. This will cause the tests to fail. You may want to reset and try again.

Happy coding!

no it does not. I miss read the explanation of the check digit. I now know that the check digit is the last digit of the typed in code before the comma.

Wait I thought I was supposed to to edit the validate_isbn.

I now know that I miss understood the check digit in general and now know that the last digit before the comma is the check digit. But the rules are only:

if length = 10 then check digit can be “X” or 0-9

or

if length = 13 then check digit can be 0-9

I checked the expected_check_digit with the debugger in vs code. It gives me the value 1, so in general it should be valid.

I didn’t touched the calculating methods because the text stated that I don’t even have to understand it. If I don’t have to understand it I also shouldn’t it no?

you don’t need to understand the two functions to fix the app

how are you checking this? because if you are talking about 1530051125,10, the expected check digit for the 9 digits 153005112 is 6, not 1

Like I said I checked the value with the debugger in VS Code. But you made me realise I was parsing all 10 or 13 characters to the main_digits variable and not just the first 9 or 12.

I will fix that now, and see where I will be after that. Thank you

I have read the assignment again and it specifically states:

In this lab, you will fix the existing code and make it function properly.

It never said I’m not allowed to change the validation method. In my understanding the tests should be able to work without knowing how the code looks like because they are just checking the output.

that’s correct, the tests expect an output, they don’t check the code you have written

You definitely can and should edit validate_isbn, but some of the changes you made weren’t necessary and might cause the tests to fail, like this one:

And this one, where you moved this validation check after assigning main_digits and given_check_digit then test against main_digiits rather than isbn:

Yes thank you I completely misunderstood the part with the check digit.
I managed to get it done yesterday.

I also tried to refactor a bit. Would it be possible to get a little feedback from you guys?
I tried to make the main() method more readable and outsourced the logic to other methods. The User Inputs gets handled inside validate_isbn(). I did not touch the calculations so I didn’t include them here.


def validate_isbn(user_input):
    if not input_is_comma_separated(user_input):
        raise ValueError("Enter comma-separated values.")
    
    values = user_input.split(",")
    isbn = values[0]
    if length_is_digit(values[1]):
        length = int(values[1])
    else:
        raise TypeError("Length must be a number.")

    main_digits = isbn[:len(isbn)-1]
    given_check_digit = isbn[length-1:]

    if length != 10 and length != 13:
        raise ValueError("Length should be 10 or 13.")
    elif len(isbn) != length:
        raise ValueError(f'ISBN-{length} code should be {length} digits long.')
    elif not isbn_is_digit(main_digits) or not validate_check_digit(given_check_digit):
        raise TypeError("Invalid character was found.")


    main_digits_list = [int(digit) for digit in main_digits]
    # Calculate the check digit from other digits
    if length == 10:
        expected_check_digit = calculate_check_digit_10(main_digits_list)
    else:
        expected_check_digit = calculate_check_digit_13(main_digits_list)
    # Check if the given check digit matches with the calculated check digit
    if (given_check_digit == expected_check_digit):
        print('Valid ISBN Code.')
    else:
        raise ValueError('Invalid ISBN Code.')


...



def input_is_comma_separated(input):
    if input.count(",") == 1:
        return True
    else:
        return False

def isbn_is_digit(isbn):
    if isbn.isdigit():
        return True
    else:
        return False

def length_is_digit(length):
    if length.isdigit():
        return True
    else:
        return False

def validate_check_digit(check_digit):
    numbers = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
    if check_digit in numbers or check_digit == "X":
        return True
    else:
        False

def main():
    user_input = input('Enter ISBN and length: ')
 
    try:
        validate_isbn(user_input)
    except ValueError as e:
        print(f"{e}")
    except TypeError as e:
        print(f"{e}")

main()