Cannot Cast float to int in Error Handling/Validation Function

706 views Asked by At

I have a function to validate some user input (val) that begins as string input. I want the input to end up in integer format but I don't want to strip a number like 4.2 to make it 4. Instead, I want to throw an error and explain the problem to the user with a different message for each invalid type.

  • The function should first check that the input is not an empty string.
  • Then it looks for a minus sign or hypen and throws an error if any are found.
  • Next, it should check whether the string is suitable to be cast as an integer (e.g. "42"). I've used isdigit() for this.
    • If suitable, it should skip straight to converting val to an int with val = int(val).

However, if the value is not a whole number in string form, I really want to check whether it's:

  • a decimal number that can be converted without causing confusion (4.0)
  • a decimal number that should prompt an error message (4.2)
  • or a non-numerical string that should prompt an error message ("I am a string").

You can see this attempt in the code:

try:
    if val == "":
        raise ValueError("customer error 1")
    if "-" in val:
        raise ValueError("custom error 2")
    if not val.isdigit():
        try:
            val = float(val)
        except Exception:
            raise ValueError("custom error 3")
        else:
            if val % 1 != 0:
                raise ValueError("custom error 4")
            else:
                val = int(val)
    else:
        val = int(val)
    if val < 5:
        raise ValueError("custom error 5")
except ValueError as e:
    print(e)
    return False
except TypeError as e:
    print(e)
    return False
return True

After the few string operations, I'm using a nested try/except to attempt converting val to a float. If successful, the program should find out whether that float has a remainder when divided by 1. In other words, can it be made a whole number without changing its numerical value (4.0 -> 4). If yes, go ahead an make it an integer.

If the float has a remainder when divided by 1, it must be something like 4.2, rather than 4. In that case, I want to alert the user with a particular error message.

If it can't be made a float, it must be non-numerical string like "I am a string". In that case, I want to alert the user with a different message.

If it's successfully converted to an integer at any stage, I want to ensure it's not less than 5.

The code above conveys all the right error messages, until I enter a float like 7.0. I thought I'd handled this and it would be converted, but I'm evidently going wrong somewhere. I've re-written it so many times at this stage, I have to concede defeat and hope someone can explain where I going wrong.

I should say, I'm new to Python and to error handling and try/except/else/finally in particular, so simplified responses would be helpful!

1

There are 1 answers

0
Eoin On

Solved: An update for anyone else in the same position. The problem is in the handling of val immediately after the function runs. This is a validation function and is not the function that originally requests the input. Therefore, any conversion inside this function does not affect val once this function is finished running since val is not returned.

Solution in this case was to run the above validation function and then, in the caller function, convert val first to float (val = float(val)) and then to int (I used val = int(val).

Although the desired type is int, val is still a string inside the caller function, so it is necessary first to convert it to a string and then to an integer. Trying to go directly from integer to string fails if using the int() method. I'm unsure whether that's a widespread issue or not, but I gather it's often preferable to cast to float first and then to int.

The bigger lesson, for me anyway, is to provide the context of any function shared for troubleshooting. If I had provided the preceding def line, it would have been clear that the input is gathered in a separate function, and someone would probably have suggested the cause.