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

Can't generate schema when typing.Never is involved #1038

Open
nbraud opened this issue Oct 26, 2023 · 3 comments
Open

Can't generate schema when typing.Never is involved #1038

nbraud opened this issue Oct 26, 2023 · 3 comments
Assignees

Comments

@nbraud
Copy link

nbraud commented Oct 26, 2023

pydantic fails to generate a schema for typing.Never; I ran into this in a model generic over a TypeVar whose bound involved Never.

Error encountered

pydantic.errors.PydanticSchemaGenerationError: Unable to generate pydantic-core schema for typing.Never. Set arbitrary_types_allowed=True in the model_config to ignore this error or implement __get_pydantic_core_schema__ on your type to fully support it.

Test case

from pydantic import Field
from pydantic.dataclasses import dataclass
from typing import Generic, Never, TypeVar


T = TypeVar('T', None, Never)

@dataclass(frozen=True, kw_only=True)
class GenericConfig(Generic[T]):
    foo: str
    bar: str | T = Field(None)

ParsedConfig = GenericConfig[None]
ResolvedConfig = GenericConfig[Never]

Workarounds

In this particular case, removing the bounds on T works, but is highly undesirable: one could then instantiate things like GenericConfig[int] without type-checking error.

I attempted to provide the schema manually, but couldn't get that to work:

from pydantic_core import core_schema
from pydantic import GetPydanticSchema

from typing import Annotated, Never as _Never
Never = Annotated[
    _Never,
    GetPydanticSchema(
        lambda tp, handler: core_schema.no_info_after_validator_function(
                lambda _: False, handler(tp)
        )
    ),
]

I'm assuming the handler(tp) call is the problem, but I couldn't find a way to directly construct a CoreSchema.

@adriangb
Copy link
Member

I don't think typing.Never makes sense in the context of a field. It only really makes sense in the context of a function return / control flow.

@nbraud
Copy link
Author

nbraud commented Oct 26, 2023

@adriangb Not sure what you mean there: Never is the bottom type, and it's generally-useful for tracking (at the type-level) situations that cannot happen (like someObj.bar being something else than a str).

I even believe this kind of use was intended given that:

  • Never is semantically-equivalent to NoReturn, but the former was added in Py3.11 to have a more-sensible name in usecases other than a function's return type;
  • mypy type-checks that kind of code without issue.

Note: if the field's type was T (rather than bar: str | T here), the type GenericConfig[Never] would indeed be uninhabited; however, it's common to have inhabited types defined by expressions that happen to contain Never.

@davidhewitt
Copy link
Contributor

davidhewitt commented Oct 27, 2023

I can see how Never might appear in generic code. I think it would be straightforward for us to add a never_schema which can never succeed validation. For example even list[Never] is sort of reasonable to me as a typing concept; it would mean a list which cannot ever contain a value.

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

No branches or pull requests

4 participants