Type of "create_pydantic_model" is partially unknown (Python 3.11)
Opened this issue · 3 comments
Hey!
When trying to use Piccolo v1.1 with Pydantic V2, Python 3.11 and Pylance in strict mode I've got this issue:
Type of "create_pydantic_model" is partially unknown
Type of "create_pydantic_model" is "(table: type[Table], nested: bool | Tuple[ForeignKey, ...] = False, exclude_columns: Tuple[Column, ...] = (), include_columns: Tuple[Column, ...] = (), include_default_columns: bool = False, include_readable: bool = False, all_optional: bool = False, model_name: str | None = None, deserialize_json: bool = False, recursion_depth: int = 0, max_recursion_depth: int = 5, pydantic_config: ConfigDict | None = None, **schema_extra_kwargs: Unknown) -> type[BaseModel]"
Here is any way to run a FastAPI project in strict type mode? Or for now it is recommended to use it in basic mode?
And by the way, when I'm trying this (in basic mode):
Foo_pydantic = create_pydantic_model(
table=Foo,
)
def bar(foo: Foo_pydantic):
pass
I also run into an issue:
Variable not allowed in type expression
(variable) Image_schema: Unknown
Interesting - I haven't run Pylance in strict mode before. I just turned it on to have a look.
I've seen the Variable not allowed in type expression
error before. It's because create_pydantic_model
creates a new class, which is assigned to a variable. Type checkers don't like it when you use a variable as a type. Functionally it works fine, so it's OK to ignore these errors.
The way we'll fix that long term is having an alternative to create_pydantic_model
which works like this instead:
class MyModel(PiccoloPydanticModel, table=MyTable):
...
As for the Type of "create_pydantic_model" is partially unknown
error, I made this example script:
from piccolo.table import Table
from piccolo.columns import Varchar
from piccolo.utils.pydantic import create_pydantic_model
class MyTable(Table):
name = Varchar()
MyModel = create_pydantic_model(
table=MyTable,
)
def bar(model: MyModel):
pass
The cause might be that Pylance is looking at Pydantic v1 for some reason. It tries to find pydantic.config.ConfigDict
and it's can't because that's only available in Pydantic v2.
Have a quick look to see if that's the case.
Hey!
I've been trying things for a while, and I found something really quite cool, that works with basic mode.
This works with Pylance:
class Image_pydantic(
create_pydantic_model(
table=Image,
exclude_columns=(Image.parameters, Image.author),
)
):
pass
This syntax, for declaring a Pydantic model, is really interesting because it also allows us to change how we serialize specific fields.
For example, I can do this:
class Expense_pydantic(
create_pydantic_model(
table=Expense,
exclude_columns=(Expense.customer,),
nested=True,
)
):
image: Image_pydantic
And it will automatically use the above pydantic model to serialize nested data from Expense.
Another example of interesting use of this declaration:
class Customer_pydantic(
create_pydantic_model(
table=Customer,
include_columns=(
Customer.id,
Customer.email,
Customer.created_on,
Customer.updated_on,
Customer.external_token,
),
)
):
external_token: Annotated[
Optional[str],
Field(
max_length=40,
examples=["r8_FoO**********************************"],
),
] = None
@model_validator(mode="after")
def post_root(self) -> "Customer_schema":
if self.external_token is not None and len(self.external_token) > 7:
self.external_token = self.external_token[:6] + "*" * (
len(self.external_token) - 6
)
if self.external_token == "":
self.external_token = None
return self
This would share a field stored in the DB, but only give a hint about its content.
For the Pylance error on create_pydantic_model
, the only one I see is this one:
Thanks for the fast answer and for your work btw, Piccolo is trully underrated!!
@Donokami That's a really nice solution!
What I've been doing in the past is something like:
MyTableBaseModel = create_pydantic_model(MyTable)
class MyTableModel(MyTableBaseModel):
...
But what you've done is definitely cleaner. I'll modify this bit of the docs to include it.
I upgraded VSCode, and Pylance is way more aggressive now. Previously I didn't encounter any warnings with the Piccolo project, but now there are quite a few I need to look into.