NowanIlfideme / pydantic-cereal

Advanced serialization for Pydantic v2
MIT License
5 stars 0 forks source link

Pylance not working for wrapped types #56

Open AmevinLS opened 5 months ago

AmevinLS commented 5 months ago

Pylance sees the wrapped types as Any, which disables hinting, autocompletion, etc. This will be very annoying to users

AmevinLS commented 4 months ago

Currently there is one workaround that allows for correct type hinting Example:

PandasDF = cereal.wrap_type(pd.DataFrame, reader=pd_read, writer=pd_write)
PandasDFAlias = PandasDF

pdf1: PandasDF = pd.DataFrame()
pdf2: PandasDFAlias = pd.DataFrame()

The PandasDF is treated as a (variable), and therefore pdf1 doesn't have Pylance completions/support The PandasDFAlias is treated as a (type alias), and therefore pdf2 has Pylance completions/support

However this would be on the users to do, which is cumbersome/inconvenient and will often be forgotten about - overall not good.

Will investigate other options in hopes of not relying on this workaround

NowanIlfideme commented 4 months ago

Ideally we could just return a TypeAlias in the signature... https://stackoverflow.com/a/70783271 But actually the issue is deeper:

from typing_extensions import TypeAlias

MyWrappedType: TypeAlias = cereal.wrap_type(MyType, reader=my_reader, writer=my_writer)

this gives:

Invalid expression form for type alias definitionPylance[reportInvalidTypeForm](https://github.com/microsoft/pyright/blob/main/docs/configuration.md#reportInvalidTypeForm)
Call expression not allowed in type expressionPylance[reportInvalidTypeForm](https://github.com/microsoft/pyright/blob/main/docs/configuration.md#reportInvalidTypeForm)
AmevinLS commented 4 months ago

Yes, a type alias definition only allows some simple assignment operation. And the function always returns a variable (even if it evaluates to a type). So it's probably impossible to return a type alias directly from the wrap_type method

NowanIlfideme commented 3 months ago

I have come to the conclusion that it's impossible to make a "valid" type form here... so I guess we should suggest the following?

MyWrappedType: TypeAlias = cereal.wrap_type(MyType, ...)  # type: ignore

That worked for Pyright 😄

Unfortunately, MyWappedType: TypeAlias[MyType] = ... # type: ignore did NOT work for Pyright, as it broke downstream!

AmevinLS commented 3 months ago

I might've found a solution:

from typing import NewType

MyWrappedType = NewType(
    "MyWrappedType", 
    cereal.wrap_type(MyType, ...)
)

This seems to allow the editor to parse type correctly and resolve the Variable not allowed in type expression Pylance(reportInvalidTypeForm) warning.

NowanIlfideme commented 3 months ago

Still really verbose, but I guess it works. 😄