typing recursive function with nested type

Question:

background: solving some algorithm problem

Problem

I’m trying to use a recursive function with nested type in VSCode, and it keep throwing error to me. I reduced it to this

from typing import Type

NestedStr = list[str | Type["NestedStr"]]


def get_first(x: str | NestedStr) -> str:
    if isinstance(x, str):
        return x
    return get_first(x[0]) # Argument of type "str | NestedStr" cannot be assigned to parameter "x" of type "str | NestedStr" in function "get_first"


assert get_first(["a", "b"]) == "a" # No error thrown here
assert get_first([["a", "b"]]) == "a" # Argument of type "list[list[str]]" cannot be assigned to parameter "x" of type "str | NestedStr" in function "get_first"

Obviously, when x is not an str it should be a NestedStr hence it can be an infinite nested list but pylance seems not knowing it.
The code can run perfectly but the error is annoying. Is there anyway to suppress it (except "type: ignore")?

Related

Appendices

Full Error Messages

  • on recursive call get_first(x[0])
Argument of type "str | NestedStr" cannot be assigned to parameter "x" of type "str | NestedStr" in function "get_first"
  Type "str | NestedStr" cannot be assigned to type "str | NestedStr"
    Type "NestedStr" cannot be assigned to type "str | NestedStr"
      "Type[type]" is incompatible with "Type[str]"
      "Type[type]" is incompatible with "NestedStr" Pylance reportGeneralTypeIssues
  • on call with list[list[str]]
Argument of type "list[list[str]]" cannot be assigned to parameter "x" of type "str | NestedStr" in function "get_first"
  Type "list[str]" cannot be assigned to type "str | NestedStr"
    "list[str]" is incompatible with "str"
    Type "list[str]" cannot be assigned to type "NestedStr" Pylance reportGeneralTypeIssues
Asked By: Pablo LION

||

Answers:

In my view this NestedStr = list[str | Type["NestedStr"]] has to be changed to that NestedStr = list[str | "NestedStr"], as it is either a string or a concrete instance of NestedStr, but not the plain type. I haven’t checked with pylance, but mypy accepts that and doesn’t raise any issue.

Answered By: Simon Hawe

As in Pylance v2023.3.20
@Simon Hawe’s answer throws an error "NestedStr" is not defined Pylance (reportUndefinedVariable)

The current solution is like this:

from typing import Union

NestedStr = list[Union[str, "NestedStr"]]


def get_first(x: str | NestedStr) -> str:
    if isinstance(x, str):
        return x
    return get_first(x[0])
    # or the shorter and working version in next line:
    # return x if isinstance(x, str) else get_first(x[0])


assert get_first([["a", "b"]]) == "a"
Answered By: Pablo LION
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.