Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

not-an-iterable and unsubscriptable-object false positives with @overload method #8634

Closed
Jonas1312 opened this issue Apr 28, 2023 · 3 comments
Labels
Duplicate 🐫 Duplicate of an already existing issue

Comments

@Jonas1312
Copy link

Bug description

I'm having two errors not-an-iterable and unsubscriptable-object with the code below:

from typing import Generator, Iterable, List, Union, overload

from typing_extensions import Literal, assert_type


class Format1:
    def __init__(self, *args, **kwargs) -> None:
        self.data = (args, kwargs)


class Format2:
    def __init__(self, *args, **kwargs) -> None:
        self.data = (args, kwargs)


class MyClass:
    def __init__(self) -> None:
        pass

    @overload
    def my_method(
        self,
        output_format: Literal["format_1"] = "format_1",
        *,
        as_generator: Literal[False] = False
    ) -> List[Format1]:
        ...

    @overload
    def my_method(
        self,
        output_format: Literal["format_2"] = "format_2",
        *,
        as_generator: Literal[False] = False
    ) -> List[Format2]:
        ...

    @overload
    def my_method(
        self, output_format: Literal["format_1"] = "format_1", *, as_generator: Literal[True] = True
    ) -> Generator[Format1, None, None]:
        ...

    @overload
    def my_method(
        self, output_format: Literal["format_2"] = "format_2", *, as_generator: Literal[True] = True
    ) -> Generator[Format2, None, None]:
        ...

    def my_method(
        self,
        output_format: Literal["format_1", "format_2"] = "format_1",
        *,
        as_generator: bool = False
    ) -> Iterable[Union[Format1, Format2]]:
        some_data = [1, 2, 3]

        format_class = Format1 if output_format == "format_1" else Format2
        gen = (format_class(i) for i in some_data)
        if as_generator:
            return gen
        return list(gen)


def test_1() -> None:
    assert_type(MyClass().my_method(), List[Format1])
    assert_type(MyClass().my_method(as_generator=True), Generator[Format1, None, None])
    assert_type(MyClass().my_method(output_format="format_2"), List[Format2])
    assert_type(
        MyClass().my_method(output_format="format_2", as_generator=True),
        Generator[Format2, None, None],
    )


def test_2() -> None:
    my_obj = MyClass()
    ret = my_obj.my_method()
    print(ret)

    assert_type(ret, List[Format1])

    assert isinstance(ret, List)
    assert all(isinstance(x, Format1) for x in ret)  # pylint not-an-iterable error here
    assert ret[0].data == ((1,), {})  # pylint unsubscriptable-object error here


if __name__ == "__main__":
    test_2()

pyright does not throw any errors with the code written in test_1. So pyright is able to figure out the proper return types thanks to the different @overload.

But pylint raises some errors in test_2, even though the code runs well.

I am not sure if it's a pylint bug, or if I didn't @overload the method my_method properly.

Thanks

Configuration

No response

Command used

pylint mre.py

Pylint output

mre.py:89:47: E1133: Non-iterable value ret is used in an iterating context (not-an-iterable)
mre.py:90:11: E1136: Value 'ret' is unsubscriptable (unsubscriptable-object)

Expected behavior

pylint should not raise those errors since pyright can identify the return types properly, and the test_2 passes

Pylint version

pylint 2.17.3
astroid 2.15.4
Python 3.7.15 (default, Nov 24 2022, 12:02:37)

OS / Environment

macos

Additional dependencies

pyright==1.1.293

@Jonas1312 Jonas1312 added the Needs triage 📥 Just created, needs acknowledgment, triage, and proper labelling label Apr 28, 2023
@mbyrnepr2
Copy link
Member

Thanks for the report @Jonas1312! I think this is a duplicate of pylint-dev/astroid#1015.

@mbyrnepr2
Copy link
Member

mbyrnepr2 commented Apr 28, 2023

There is also #5712 and #4696 so there could be multiple duplicates already; would need to dig into those to be sure.

@mbyrnepr2 mbyrnepr2 added Duplicate 🐫 Duplicate of an already existing issue and removed Needs triage 📥 Just created, needs acknowledgment, triage, and proper labelling labels Apr 28, 2023
@jacobtylerwalls jacobtylerwalls closed this as not planned Won't fix, can't repro, duplicate, stale Apr 28, 2023
@Jonas1312
Copy link
Author

My bad! I didn't find the already existing issues... 🙏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Duplicate 🐫 Duplicate of an already existing issue
Projects
None yet
Development

No branches or pull requests

3 participants