Python try except with if else - KeyError if no value for input of first condition is passed

118 Views Asked by At

Assessment for the names "max" and "alex" should be overall true, iff all three inputs (healthy, tall, rich) are 1. If at least one of the inputs is equal to 0, then "false" should be returned.

However, it seems that a value for the input of the first condition (in this case healthy) always has to be passed in order not to get the KeyError. How can that be changed?

See in the following code snippet that for test 2 I get a KeyError. In comparison, for test 3 I provide a value for "healthy" and the result is as expected.

import pytest


def function(x: dict) -> str:
    try:
        if x["name"] in ["max", "alex"]:
            if x["healthy"] != 1:
                return "false"
            if x["tall"] != 1:
                return "false"
            if x["rich"] != 1:
                return "false"
        return "true"
    except KeyError:
        return "input_is_missing"


class TestEvaluate:
    false = "false"
    true = "true"
    input_is_missing = "input_is_missing"

    @pytest.mark.parametrize(
        "inputs, expected",
        [
            # Test 1
            (
                {
                    "name": "max",
                    "healthy": 0,
                },
                false,
            ),
            # Test 2
            (
                {
                    "name": "max",
                    "tall": 0,
                },
                false,
            ),
            # Test 3
            (
                {
                    "name": "max",
                    "healthy": 1,
                    "tall": 0,
                },
                false,
            ),
        ],
    )
    def test_valid_inputs(self, inputs, expected):
        assert function(inputs) == expected
3

There are 3 best solutions below

3
user22685657 On

To address the issue of receiving a KeyError when the "healthy" input is missing, you can modify the code by checking for the presence of the "healthy" key in the input dictionary before accessing its value. Here's an updated version of the code:

def function(x: dict) -> str:
    try:
        if x["name"] in ["max", "alex"]:
            
            # Check if the "healthy" key is present in the input dictionary
            if "healthy" not in x:
                return "false"

            if x["healthy"] != 1:
                return "false"
            
            if x["tall"] != 1:
                return "false"
            
            if x["rich"] != 1:
                return "false"
            
            return "true"
        
        return "false"

    except KeyError:
        return "input_is_missing"

In this updated code, if the "healthy" key is missing from the input dictionary, the function immediately returns "false" without checking the other conditions. This ensures that a KeyError is not raised and that the proper output is returned.

0
Bijo Thomas On

You need to first check if any of healthy, tall or rich are explicitly set as 0. If so, return false.

Once that's sorted, your only case when the return value is true is when all of them are available and are set to 1. In that case return true. When accessing the values, if any of them are missing, you will automatically get a KeyError and hence the response input_is_missing.

def function(x: dict) -> str:
    try:
        if x["name"] in ["max", "alex"]:
            if "healthy" in x and x["healthy"] == 0:
                return "false"
            if "tall" in x and x["tall"] == 0:
                return "false"
            if "rich" in x and x["rich"] == 0:
                return "false"
            if x["healthy"] == 1 and x["tall"] == 1 and x["rich"] == 1:
                return "true"
    except KeyError:
        return "input_is_missing"
2
Guillaume On

You could use the construct if "healthy" in x and ..., but I suggest using the get method of dictionaries, which can return a default if the key does not exist.

Your code then becomes:

def function(x: dict) -> str:
        if x["name"] in ["max", "alex"]:
            if x.get("healthy", 0) != 1:
                return "false"
            if x.get("tall", 0) != 1:
                return "false"
            if x.get("rich", 0) != 1:
                return "false"
        return "true"

That way, you will never get a KeyError, which might or might not be what you want.

Edit after comment, if you do want the "input_is_missing" return:

def function(x: dict) -> str:
        if x["name"] in ["max", "alex"]:
            missing=[]
            for characteritic in ["healthy", "tall", "rich"]:
                if characteristic in x:
                    if x[characterictic] != 1:
                        return "false"
                else:
                    missing.append(characteritic)
            if missing:
                return "input_is_missing" # you even know which one
            else:
                return "true"
        return "true"