Skip to content

too-many-branches (PLR0912)

Derived from the Pylint linter.

What it does

Checks for functions or methods with too many branches, including (nested) if, elif, and else branches, for loops, try-except clauses, and match and case statements.

By default, this rule allows up to 12 branches. This can be configured using the lint.pylint.max-branches option.

Why is this bad?

Functions or methods with many branches are harder to understand and maintain than functions or methods with fewer branches.

Example

Given:

def capital(country):
    if country == "Australia":
        return "Canberra"
    elif country == "Brazil":
        return "Brasilia"
    elif country == "Canada":
        return "Ottawa"
    elif country == "England":
        return "London"
    elif country == "France":
        return "Paris"
    elif country == "Germany":
        return "Berlin"
    elif country == "Poland":
        return "Warsaw"
    elif country == "Romania":
        return "Bucharest"
    elif country == "Spain":
        return "Madrid"
    elif country == "Thailand":
        return "Bangkok"
    elif country == "Turkey":
        return "Ankara"
    elif country == "United States":
        return "Washington"
    else:
        return "Unknown"  # 13th branch

Use instead:

def capital(country):
    capitals = {
        "Australia": "Canberra",
        "Brazil": "Brasilia",
        "Canada": "Ottawa",
        "England": "London",
        "France": "Paris",
        "Germany": "Berlin",
        "Poland": "Warsaw",
        "Romania": "Bucharest",
        "Spain": "Madrid",
        "Thailand": "Bangkok",
        "Turkey": "Ankara",
        "United States": "Washington",
    }
    city = capitals.get(country, "Unknown")
    return city

Given:

def grades_to_average_number(grades):
    numbers = []
    for grade in grades:  # 1st branch
        if len(grade) not in {1, 2}:
            raise ValueError(f"Invalid grade: {grade}")

        if len(grade) == 2 and grade[1] not in {"+", "-"}:
            raise ValueError(f"Invalid grade: {grade}")

        letter = grade[0]

        if letter in {"F", "E"}:
            number = 0.0
        elif letter == "D":
            number = 1.0
        elif letter == "C":
            number = 2.0
        elif letter == "B":
            number = 3.0
        elif letter == "A":
            number = 4.0
        else:
            raise ValueError(f"Invalid grade: {grade}")

        modifier = 0.0
        if letter != "F" and grade[-1] == "+":
            modifier = 0.3
        elif letter != "F" and grade[-1] == "-":
            modifier = -0.3

        numbers.append(max(0.0, min(number + modifier, 4.0)))

    try:
        return sum(numbers) / len(numbers)
    except ZeroDivisionError:  # 13th branch
        return 0

Use instead:

def grades_to_average_number(grades):
    grade_values = {"F": 0.0, "E": 0.0, "D": 1.0, "C": 2.0, "B": 3.0, "A": 4.0}
    modifier_values = {"+": 0.3, "-": -0.3}

    numbers = []
    for grade in grades:
        if len(grade) not in {1, 2}:
            raise ValueError(f"Invalid grade: {grade}")

        letter = grade[0]
        if letter not in grade_values:
            raise ValueError(f"Invalid grade: {grade}")
        number = grade_values[letter]

        if len(grade) == 2 and grade[1] not in modifier_values:
            raise ValueError(f"Invalid grade: {grade}")
        modifier = modifier_values.get(grade[-1], 0.0)

        if letter == "F":
            numbers.append(0.0)
        else:
            numbers.append(max(0.0, min(number + modifier, 4.0)))

    try:
        return sum(numbers) / len(numbers)
    except ZeroDivisionError:
        return 0

Options