pythonpycharmsonarlint

How to reduce Cognitive Complexity in this Python method


I am faced with a challenge.

I have an Python method implemented and the SonarLint plugin of my PyCharm warns me with the message: "Refactor this function to reduce its Cognitive Complexity from 19 to the 15 allowed." but I can't see how to reduce the complexity.

My Python method is:

def position(key):
    if key == 'a':
        return 0
    elif key == 'b':
        return 1
    elif key == 'c':
        return 2
    elif key == 'd':
        return 3
    elif key == 'e':
        return 4
    elif key == 'f':
        return 5
    elif key == 'g':
        return 6
    elif key == 'h':
        return 7
    elif key == 'i':
        return 8
    elif key == 'j':
        return 9
    elif key == 'k':
        return 10
    elif key == 'l':
        return 11
    elif key == 'm':
        return 12
    elif key == 'n':
        return 13
    elif key == 'ñ':
        return 14
    elif key == 'o':
        return 15
    elif key == 'p':
        return 16
    elif key == 'q':
        return 17
    else:
        logger.info('error')

And the warning of SonarLint is:

enter image description here

And if I click on show issue locations it gives me the explanation of how the Cognitive Complexity is calculated: enter image description here

I can't see how to reduce the complex of this function. I know that I can implement another method with the same behaviour using things like the ascii code, but it's not the point of this question.

The summary of the question is how can I follow the suggestion of SonarLint, I mean, how can I reduce the Cognitive Complexity from 19 to the 15 of this particular method.

Something I've noticed is that if I remove elif statements until I have only 14 characters cases, the warning magically disappears.


Solution

  • I've found what's happening. The Plugin SonarLint has a maximum number of Cognitive Complexity, as you can see in this capture:

    enter image description here

    So SonarLint doesn't say you that you can simplify your method, it tells you that this method is more complex than the prefixed limit that SonarLint has setted.

    This is the reason because if I delete elif until I reach the magic number of 15 for the Cognitive Complexity the warning magically disappears.

    ¡¡WARNING!! It's not recommendable to increase the SonarLint limit of Cognitive Complexity. The most advisable option is to refactor your method and find another way to do the same.

    In my case I've implemented the next method instead (there are another shorter solutions, but because I have to use spanish alphabet I decided to use what for mi is the most readable solution):

     def position(key: str) -> (int, None):
        char_map = {
            'a': 0,
            'b': 1,
            'c': 2,
            'd': 3,
            'e': 4,
            'f': 5,
            'g': 6,
            'h': 7,
            'i': 8,
            'j': 9,
            'k': 10,
            'l': 11,
            'm': 12,
            'n': 13,
            'ñ': 14,
            'o': 15,
            'p': 16,
            'q': 17,
            'r': 18,
            's': 19,
            't': 20,
            'u': 21,
            'v': 22,
            'w': 23,
            'x': 24,
            'y': 25,
            'z': 26
        }
    
        try:
            output = char_map[key]
        except KeyError:
            logger.error('KeyError in position() with the key: ' + str(key))
            return None
    
        return output