MaxPowers
MaxPowers

Reputation: 5486

'Missing return statement' in simple conditional structure

The return type of the below function depends on the argument passed to path: if it is None the function returns a string, if it is a string the function returns None, and in all other possible cases, the function does not return at all. However, mypy reports

error: Missing return statement

What am I missing here?

import json
from typing import Optional

def to_json(data: dict, path: Optional[str] = None) -> Optional[str]:
    if path is None:
        return json.dumps(data)
    elif isinstance(path, str):
        with open(path, 'w') as file:
            json.dump(data, file)
    else:
        raise TypeError('Unsupported type for ``path``.')

Upvotes: 1

Views: 8519

Answers (4)

hoefling
hoefling

Reputation: 66171

mypy warns on missing return types by default, so you can turn it off explicitly:

$ mypy --no-warn-no-return spam.py

or turn off the particular check for the particular line only:

def to_json(data: Dict, path: Optional[str] = None) -> Optional[str]:  # type: ignore[return]
    ...

However, your function has different return types depending on the input. I would add an overloaded signature to handle these:

from typing import Dict, Optional, overload

# when path is provided, the function returns
@overload
def to_json(data: Dict, path: str) -> str: ...

# when path is not provided, the function returns None
@overload
def to_json(data: Dict) -> None: ...

# your actual impl
def to_json(data, path=None):
    if path is None:
        ...

Upvotes: 4

Paritosh Singh
Paritosh Singh

Reputation: 6246

First things first, your code is valid python. I believe mypy seems to be configured according to PEP8 recommendations for returns but is more strict about it since it has to enforce typechecks. The relevant section:

Be consistent in return statements. Either all return statements in a function should return an expression, or none of them should. If any return statement returns an expression, any return statements where no value is returned should explicitly state this as return None, and an explicit return statement should be present at the end of the function (if reachable).

Yes:

def foo(x):
    if x >= 0:
        return math.sqrt(x)
    else:
        return None

No:

def foo(x):
    if x >= 0:
        return math.sqrt(x)

So, for your code, just be explicit about return None in all branches where you do not return anything else.

Upvotes: 1

Jean-François Fabre
Jean-François Fabre

Reputation: 140148

not explicitly returning something from all branches makes the static analysis fail: it's seen as an omission (and considered as bad practice).

Just make the return None explicit in the else part (no need where you're rasing an exception)

elif isinstance(path, str):
    with open(path, 'w') as file:
        json.dump(data, file)
    return None

Upvotes: 2

Vaibhav Jadhav
Vaibhav Jadhav

Reputation: 2076

Just add return None to the code or return -1 or any such kind of return at the end of code.

Upvotes: 0

Related Questions