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 TypeVar with Identical Bound and Default #9418

Open
4 of 13 tasks
rmorshea opened this issue May 9, 2024 · 1 comment
Open
4 of 13 tasks

Support TypeVar with Identical Bound and Default #9418

rmorshea opened this issue May 9, 2024 · 1 comment
Labels
Change Suggested alteration to pydantic, not a new feature nor a bug feature request

Comments

@rmorshea
Copy link

rmorshea commented May 9, 2024

Initial Checks

  • I have searched Google & GitHub for similar requests and couldn't find anything
  • I have read and followed the docs and still think this feature is missing

Description

The Problem

Currently Pydantic does not support TypeVar with more than one of a bound, default, or constraints declared. This is a problem because users are forced to choose between better usability or greater correctness. As described in the motivations for the PEP which added TypeVar defaults declaring both a bound a default is relatively common:

from typing_extensions import TypeVar

T = TypeVar("T", bound=int, default=int)

def f(x: T = 1) -> T:
    return x

f("hello")  # error because str not subtype of int

If we're forced to only declare a default we won't get appropriate type warnings:

from typing_extensions import TypeVar

T = TypeVar("T", default=int)

def f(x: T = 1) -> T:
    return x

f("hello")  # no error

Partial Solution

After inspecting the downstream code which handles bounds and defaults, it appears that it would relatively easy to at least support the case of a TypeVar with an identical bound and default declared. From my anecdotal experience, this likely covers the majority of cases where someone might want to specify both a bound and a default.

Supporting this would involve rewriting:

        if (bound is not None) + (len(constraints) != 0) + (default is not None) > 1:
            raise NotImplementedError(
                'Pydantic does not support mixing more than one of TypeVar bounds, constraints and defaults'
            )

        if default is not None:
            return self.generate_schema(default)
        elif constraints:
            return self._union_schema(typing.Union[constraints])  # type: ignore
        elif bound:
            schema = self.generate_schema(bound)
            schema['serialization'] = core_schema.wrap_serializer_function_ser_schema(
                lambda x, h: h(x), schema=core_schema.any_schema()
            )
            return schema
        else:
            return core_schema.any_schema()

To look more like:

        if len(constraints) != 0:
            if (bound is not None or default is not None):
                raise RuntimeError(...)
            return self._union_schema(typing.Union[constraints])
        if bound is not None and default is not None and bound != default:
            raise RuntimeError(...)
        else:
            schema = generate_schema(bound or default)
            if bound is not None:
                schema['serialization'] = core_schema.wrap_serializer_function_ser_schema(
                    lambda x, h: h(x), schema=core_schema.any_schema()
                )
            return schema

The main question I have is how feasible it is to actually check bound != default. Besides that, this seems fairly sound.

Affected Components

@rmorshea rmorshea changed the title Support TypeVar with Identical bound and default Support TypeVar with Identical Bound and Default May 9, 2024
@sydney-runkle sydney-runkle added the Change Suggested alteration to pydantic, not a new feature nor a bug label May 16, 2024
@sydney-runkle
Copy link
Member

@rmorshea,

Thanks for the feature request. I've added the label change here as well.

At a first glance, your approach sounds good. Feel free to open a PR with the changes, and I can do a more thorough review! We'll want to test this pretty thoroughly before we introduce the change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Change Suggested alteration to pydantic, not a new feature nor a bug feature request
Projects
None yet
Development

No branches or pull requests

2 participants