mypy icon indicating copy to clipboard operation
mypy copied to clipboard

Support for Partial types

Open hackaugusto opened this issue 2 years ago • 4 comments

Feature

File t.py:

from typing_extensions import TypedDict


class Foo(TypedDict):
    x:int
    y:int


foo: Partial[Foo] = {'x': 1}
# reveal_type(foo) -> TypedDict('t.Foo?', {'x'?: builtins.int, 'y'?: builtins.int})

Pitch

For some uses cases, e.g. processing PATCH requests on a web server, we usually want to allow a partial version of the original model. Currently this must be done manually, and that can be a bit error prone since one may forget to update the partial model. The Partial type annotation would transform the original type into its optional version.

Related to: https://github.com/python/mypy/issues/4128 Note: Examples taken from https://stackoverflow.com/questions/69091758/python-typehint-subsetpartial-of-an-typeddict

hackaugusto avatar Sep 20 '22 09:09 hackaugusto

"Partial types" already means something else within mypy, so it may not be the best name.

JelleZijlstra avatar Sep 21 '22 02:09 JelleZijlstra

I would like to second this idea. Partial (or any other more convenient name) could also be applied to dataclasses and other record-like classes, like pydantic. Partials are very useful to express updates/patches of pre-existing types.

jdinunzio avatar Sep 25 '22 11:09 jdinunzio

I think the naming needs to be discussed separately.

I find it very useful for representing existing types of updates/patches. Here are some cases.

Case.1 It can be very tedious when the number of arguments is large. When the number of arguments is small, there is no problem because it can be written as follows.

    def foo_setter(arg: LibraryFoo, x: int | None = None, y = int | None = None): 
        ...

However, when the number of arguments becomes very large, it becomes tiresome.

Case.2 The scope of the modification can be kept small and type-safe. Then, when z is added to the library, it is resistant to change and its sphere of influence is closed to business_logic.py. Increases maintainability even with more arguments.

# Library code someone made this code
from typing import TypedDict
from final_class import final


@final
class LibraryFoo(TypedDict):  # We cannot inherit/replace it
    x: int
    y: int

# -----------
# Application code

from typing import Unpack

# application_utility.py
def foo_setter(arg: LibraryFoo, **kwargs: Unpack[LibraryFoo]):
    for k in kwargs:
        arg[k] = kwargs[k]


# business_logic.py
vec = {'x': 0, 'y': 0}
foo_setter(vec, x=1)  # Error: Argument missing for parameter "y" Pylance(reportGeneralTypeIssues)
print(vec)
foo_setter(vec, y=2)  # Error: Argument missing for parameter "x" Pylance(reportGeneralTypeIssues)
print(vec)
foo_setter(vec, x=10

It would be very nice and type safe if we could write the following.

def foo_setter(arg: LibraryFoo, **kwargs: Partial[Unpack[LibraryFoo]]): ...

foo_setter(vec, x=1) and foo_setter(vec, y=2) will no longer be errors.

intptr-t avatar Jun 30 '23 14:06 intptr-t

Made a thread at Python Discussions: https://discuss.python.org/t/introduce-partial-for-typeddict/45176/11 Aggregating all links in one place.

USSX-Hares avatar Feb 07 '24 14:02 USSX-Hares