microsoft / pylance-release

Documentation and issues for Pylance
Creative Commons Attribution 4.0 International
1.67k stars 770 forks source link

type hinting for circular referenced TypedDict #6007

Closed BerendKemper closed 2 weeks ago

BerendKemper commented 2 weeks ago

Here is a situation where i am trying to provide type hinting for Mongo DB query parameters (as an example). A lot of Mongo DB query properties are prefixed by $. Python class syntax does not allow properties that are prefixed by $ and additionally and and or are special reserved language keys. For those reasons i am bound to implement a TypedDict in the form of a TypedDict constructor instead of class extension. However, below i did provided two approuches to define a TypedDict that takes a few Mongo DB query properties.

# from pypi
from typing import TypedDict, NewType, Literal, Union, ForwardRef
from __future__ import annotations

# script
FilterRegex = TypedDict('FilterRegex', {'$regex': str, '$options': Literal['i']})
FilterIn = TypedDict('FilterIn', {"$in": list[int, str, bool]})
FilterValue = Union[FilterIn, FilterRegex]

FilterEntry = NewType('FilterEntry', dict[str, FilterValue])

_Filters: Filters = ForwardRef('Filters')
FilterList = NewType('FilterList', list[Union[FilterEntry, _Filters]])
Filters = TypedDict('Filters', {'$and': FilterList, '$or': FilterList})

class Filters2(TypedDict):
    _and: list[Union[FilterEntry, 'Filters2']]
    _or: list[Union[FilterEntry, 'Filters2']]

class TypedParams(TypedDict):
    filter: Union[FilterEntry, Filters]
    filter2: Union[FilterEntry, Filters2]
erictraut commented 2 weeks ago

You are not allowed to use variables within a type expression. Since _Filters is a variable, it cannot be used in the type expression used to define FilterList in your example.

You can use quoted type expressions (forward references) within the functional form of a TypedDict definition and for NewType definitions.

FilterList = NewType("FilterList", list[Union[FilterEntry, "Filters"]])

With this change to your code, pylance provides the completion suggestions you're looking for.

For more details about allowed type expressions, refer to this section of the Python typing spec.

BerendKemper commented 2 weeks ago

Wauw i thaught i had tried that before already. Guess the previous time i still had something wired up wrong. This time it worked like you said it does. Thanks