Skip to content

[typing BUG] PatchDict Type checking error #1441

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
sxoinas12 opened this issue Apr 9, 2025 · 11 comments
Closed

[typing BUG] PatchDict Type checking error #1441

sxoinas12 opened this issue Apr 9, 2025 · 11 comments

Comments

@sxoinas12
Copy link

sxoinas12 commented Apr 9, 2025

Describe the bug

when using PatchDict I do get the below error when I perform my type checking:

Run Basedpyright type checking...........................................Failed
- hook id: basedpyright
- exit code: 1

Type "dict[Unknown, Unknown]" is already specialized

Example:

i have the below schema

from ninja import Schema, PatchDict

class UpdateTextSectionData(Schema):
    title: str
    content: str
    event_id: uuid.UUID

@text_sections_api.patch(
    "/{text_section_id}",
)
def update_text_section(
    request: WSGIRequest,
    text_section_id: uuid.UUID,
    text_section_data: PatchDict[UpdateTextSectionData], # error is being raised for this line
)

when using it in my view with PatchDict as described in your documentation I do get the above type error, which i believe it's expected since you already it have it as an annotated type here

Is there a mistake in your documentation ? I would expect this to do what it describes and make my fields optional.

Versions:

  • Python version: 3.13.0
  • Django version: 5.1.5
  • Django-Ninja version: 1.4.1
  • Pydantic version: 2.11.3
@sxoinas12 sxoinas12 changed the title [BUG] [BUG] PatchDict Type error Apr 9, 2025
@sxoinas12 sxoinas12 changed the title [BUG] PatchDict Type error [BUG] PatchDict usage Type error Apr 9, 2025
@sxoinas12 sxoinas12 changed the title [BUG] PatchDict usage Type error [BUG] PatchDict Type checking error Apr 9, 2025
@vitalik
Copy link
Owner

vitalik commented Apr 9, 2025

@sxoinas12 could you share what do you use for typechecing (exact version and command you are running to type check it ? )

@sxoinas12
Copy link
Author

sxoinas12 commented Apr 9, 2025

@vitalik Thanks for coming back to this .

I am using "basedpyright>=1.28.1", and the command to test this is simply basedpyright
Our settings are the below

[tool.pyright]
pythonPlatform = "Linux"
reportUnsupportedDunderAll  = "none"
typeCheckingMode            = "standard"    # "off", "basic", "standard", "strict"

simply by running basedpyright you can reproduce -> error: Type "dict[Unknown, Unknown]" is already specialized

@vitalik vitalik changed the title [BUG] PatchDict Type checking error [typing BUG] PatchDict Type checking error Apr 9, 2025
@Ige-kun
Copy link

Ige-kun commented Apr 30, 2025

This is also reproducible with the upstream pyright using its latest version (1.1.400) with the configuration
typeCheckingMode = "standard" (the default).

@vitalik
Copy link
Owner

vitalik commented Apr 30, 2025

@Ige-kun @sxoinas12 - can you check if placing this before you code will work ?

from typing import TYPE_CHECKING, Generic, Any, TypeVar

if TYPE_CHECKING:
    T = TypeVar('T')
    class PatchDict(dict[Any, Any], Generic[T]):
        pass

@khurramshahzad456
Copy link

I tried above code and start getting an other type error

Image

@sxoinas12
Copy link
Author

Hi @vitalik. Thanks for coming back. I tried your suggested solution.

here is the full snippet and the error

from typing import TYPE_CHECKING, Generic, Any, TypeVar
from ninja import Schema, PatchDict

if TYPE_CHECKING:
    T = TypeVar("T")

    class PatchDict(dict[Any, Any], Generic[T]):
        pass

class UpdateTextSectionData(Schema):
    title: str
    content: str
    event_id: uuid.UUID


@text_sections_router.patch(
    "events/{event_id}/text-sections/{text_section_id}",
    response={204: SuccessHullAPIResponse, 403: FailureHullAPIResponse},
)
def update_event_text_section(
    request: WSGIRequest,
    event_id: uuid.UUID,
    text_section_id: uuid.UUID,
    text_section_payload: PatchDict[UpdateTextSectionData],
) -> tuple[int, HullAPIResponse]:

Error

Image
/Users/konstantinosschoinas/work.nosync/hull/backend/src/text_sections/update_text_section/views.py
  /Users/konstantinosschoinas/work.nosync/hull/backend/src/text_sections/update_text_section/views.py:22:27 - error: Type "PatchDict" is not assignable to declared type "type[PatchDict[T@PatchDict]]"
    Type "Annotated" is not assignable to type "type[PatchDict[T@PatchDict]]" (reportAssignmentType)
  /Users/konstantinosschoinas/work.nosync/hull/backend/src/text_sections/update_text_section/views.py:61:36 - error: Cannot access attribute "dict" for class "PatchDict[UpdateTextSectionData]"
    Attribute "dict" is unknown (reportAttributeAccessIssue)
2 errors, 0 warnings, 0 notes

Notice the later error comes because i try to do **text_section_payload.dict later in the code.

@nikatlas
Copy link

nikatlas commented Jun 3, 2025

@vitalik

I think the issue is that you annotate the PatchDict as a dictionary.
The PatchDict is actually a descriptor that returns a dictionary based on a Schema so it is more like a Generic of dict (type of PatchDict[ ANY_SCHEMA ] -> dict ).

I tried this and works with pyright.

type PatchDict[T: Schema] = Annotated[dict, "<PatchDict>"]

It does look incomplete to me though or not the proper way to type this descriptor. Ideally the PatchDictUtil class should be typed such that the custom if TYPE_CHECKING is not needed. But I know that typing descriptors is not easy.

If I find something more precise I will let you know. Let me know if you know how this typing can be achieved in a more complete way.

Note: This may only work on python 3.12 as generics types where introduced then.

@nikatlas
Copy link

nikatlas commented Jun 3, 2025

@vitalik I just realised your snippet above is equivalent to my snippet provided above and backwards compatible to older versions.

The issue mentioned by the other guys is because the type definition is declared twice both inside the library and then they try to overwrite it.

I edited the library internally and it works like a charm.

Could we merge your fix and make a release?

@vitalik
Copy link
Owner

vitalik commented Jun 3, 2025

@nikatlas @sxoinas12 @khurramshahzad456 - can you check against this branch ? https://github.com/vitalik/django-ninja/tree/1441-patch-dict-type-check

@sxoinas12
Copy link
Author

I tested it with

uv pip install git+https://github.com/vitalik/django-ninja.git@4f0bbbc61f5d9bd4100c9965a020edce4f93bf9e

(.venv) konstantinosschoinas@Konstantinoss-MacBook-Pro backend % basedpyright
0 errors, 0 warnings, 0 notes

@sxoinas12
Copy link
Author

Fixed with this one Thank you

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants