Skip to content
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

Support for Partial types #13695

Open
hackaugusto opened this issue Sep 20, 2022 · 4 comments
Open

Support for Partial types #13695

hackaugusto opened this issue Sep 20, 2022 · 4 comments
Labels

Comments

@hackaugusto
Copy link
Contributor

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: #4128
Note: Examples taken from https://stackoverflow.com/questions/69091758/python-typehint-subsetpartial-of-an-typeddict

@JelleZijlstra
Copy link
Member

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

@jdinunzio
Copy link

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.

@intptr-t
Copy link

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.

@USSX-Hares
Copy link

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

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

No branches or pull requests

5 participants