[Python] Why can't Pylance fully infer the return type of this function?

Discussão em 'Python' iniciado por Stack, Fevereiro 6, 2025.

  1. Stack

    Stack Membro Participativo

    I am using Python 3.11.4, and Pydantic 2.10.0. The following is a toy example of a real-world problem.

    I have defined two Pydantic Basemodels, and created a list containing instances of both, as follows.

    import pydantic


    class Foo(pydantic.BaseModel):
    a: int
    b: int


    class Bar(pydantic.BaseModel):
    c: int
    d: int

    non_homogeneous_container = [
    Foo(a=1, b=5),
    Foo(a=7, b=8),
    Bar(c=5, d=3),
    Bar(c=15, d=12),
    ]


    I want to write a function that takes in such a list, as well as a target_type, and returns a list containing only those objects from the original list that conform to the specified target_type. I have written such a function, as below, and provided (what I believe to be) the appropriate type annotation for my type checker (Pylance, in VSCode).

    from typing import Any, Type, TypeVar

    T = TypeVar("T", bound=pydantic.BaseModel)


    def extract_objects_of_specified_type(
    mixed_up_list: list[Any],
    target_type: Type[T],
    ) -> list[T]:
    extracted_list: list[T] = []
    for each_object in mixed_up_list:
    if isinstance(each_object, target_type):
    extracted_list.append(each_object)
    return extracted_list


    Invoking my function with my mixed up list of objects, I obtain the expected list containing only objects of the target_type.

    list_of_only_foos = extract_objects_of_specified_type(
    mixed_up_list=non_homogeneous_container, target_type=Foo
    )

    print (list_of_only_foos)
    # Result: [Foo(a=1, b=5), Foo(a=7, b=8)]


    However, I have a yellow underline on the line where I invoke my function; Pylance says the argument type is partially unknown. The bit that's underlined and the associated Pylance report are as below:

    # list_of_only_foos: list[Foo] = extract_objects_of_specified_type(
    # mixed_up_list=non_homogeneous_container, target_type=Foo
    # ) ^^^^^^^^^^^^^^^^^^^^^^^^^
    # Linter report:
    # Argument type is partially unknown
    # Argument corresponds to parameter "mixed_up_list" in function "extract_objects_of_specified_type"
    # Argument type is "list[Unknown]"PylancereportUnknownArgumentType


    The linter report goes away when I annotate my input list of objects as below:

    non_homogeneous_container: list[Foo | Bar] = [
    Foo(a=1, b=5),
    Foo(a=7, b=8),
    Bar(c=5, d=3),
    Bar(c=15, d=12),
    ]


    or

    non_homogeneous_container: list[pydantic.BaseModel] = [
    Foo(a=1, b=5),
    Foo(a=7, b=8),
    Bar(c=5, d=3),
    Bar(c=15, d=12),
    ]


    I find this unsatisfactory because it obliges me to know in advance what objects are expected to be in the list I feed to my function.

    I have tried to get around this issue by wrapping my function in a class that employs a Generic (below), but this made no difference.

    class ExtractSpecificType(Generic[T]):
    @staticmethod
    def extract_objects_of_specified_type(
    mixed_up_list: list[Any],
    target_type: Type[T],
    ) -> list[T]:
    extracted_list: list[T] = []
    for each_object in mixed_up_list:
    if isinstance(each_object, target_type):
    extracted_list.append(each_object)
    return extracted_list


    My function as originally constructed does what I want it to do - my question is about WHY the type checker is unhappy. Is my type annotation imprecise in some way? If so, what should I do differently?

    Thank you.

    EDIT

    user2357112's comment and InSync's answer indicate that that this behaviour has something to do with the prevailing type-checker settings about when and where to warn about missing/ambiguous type annotations. For context, I have reproduced my VSCode type-checking settings below.

    "python.analysis.typeCheckingMode": "standard",
    "python.analysis.diagnosticSeverityOverrides": {
    "reportGeneralTypeIssues": true,
    "reportUnknownArgumentType": "warning",
    "reportUnknownParameterType": "warning",
    "reportMissingTypeArgument ": "warning",
    "reportMissingParameterType": "warning",
    "reportReturnType": "error",
    "reportUnusedImport": "warning",
    "reportUnnecessaryTypeIgnoreComment": "error"
    },

    Continue reading...

Compartilhe esta Página