Skip to content

False positive for inconsistent-return-statements with method annotated with NoReturn return type #8747

Closed
@kdestin

Description

@kdestin

Bug description

repro.py

from typing import NoReturn

class Foo:
    def _never_returns() -> NoReturn:
        raise Exception

    def bar(self) -> int:
        try:
            return 1
        except Exception:
            self._never_returns()

Configuration

Default Config

Command used

pylint --disable=all --enable=inconsistent-return-statements repro.py

Pylint output

************* Module repro
repro.py:7:4: R1710: Either all return statements in a function should return an expression, or none of them should. (inconsistent-return-statements)

------------------------------------------------------------------
Your code has been rated at 8.89/10 (previous run: 0.00/10, +8.89)

Expected behavior

------------------------------------
Your code has been rated at 10.00/10

Pylint version

My pylint configuration is pinned to 


pylint 2.15.8
astroid 2.13.5
Python 3.10.6 (main, Mar 10 2023, 10:55:28) [GCC 11.3.0]


But I was able to repro this on the latest released version of pylint (2.17.4 at time of writing).

OS / Environment

$ lsb_release -a
Distributor ID:	Ubuntu
Description:	Ubuntu 22.04.2 LTS
Release:	22.04
Codename:	jammy
$ uname -r
5.15.0-72-generic

Additional dependencies

No response


I did an initial investigation, and might have an idea of what's going on:

  • During the inconsistent-return-statements lint, there's an attempt made infer whether the return type of a function call is NoReturn.

    def _is_function_def_never_returning(self, node: nodes.FunctionDef) -> bool:
    """Return True if the function never returns, False otherwise.
    Args:
    node (nodes.FunctionDef): function definition node to be analyzed.
    Returns:
    bool: True if the function never returns, False otherwise.
    """
    if isinstance(node, nodes.FunctionDef) and node.returns:
    return (
    isinstance(node.returns, nodes.Attribute)
    and node.returns.attrname == "NoReturn"
    or isinstance(node.returns, nodes.Name)
    and node.returns.name == "NoReturn"
    )

  • But _is_function_def_never_returning only inspects the return type if the node passed in is a nodes.FunctionDef. But calling node.func.inferred()[0] on the method call (e.g. self._never_returns()) returns the corresponding method definition node as type astroid.BoundMethod. Since that isn't a nodes.FunctionDef, _is_function_def_never_returning never even looks to see if the return type is NoReturn.

    funcdef_node = node.func.inferred()[0]
    if self._is_function_def_never_returning(funcdef_node):

Metadata

Metadata

Assignees

No one assigned

    Labels

    False Positive 🦟A message is emitted but nothing is wrong with the code

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions