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

Add support for typing.Never #1579

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Open

Conversation

changhc
Copy link
Contributor

@changhc changhc commented Dec 10, 2024

Change Summary

Add support for typing.Never.

Validation

The validator implementation might look a bit weird. This is because of RootModel. Even though it doesn't really make sense, I assume that the following should work:

from typing import Never
from pydantic import RootModel

v = RootModel[Never]()

and because RootModel passes PydanticUndefined to the validator when no data is provided, the validator needs to work with PydanticUndefined. If we don't expect RootModel[Never]() to ever work, we can simplify the implementation and simply reject all values, but there might be another issue: users might wonder how the following works while RootModel does not:

from typing import Never
from pydantic import BaseModel

class Model(BaseModel):
    a: Never

Also, simply rejecting everything in the validator means that the validated model instance will not contain any value for the Never fields. When users try to access those fields, they will get an error, but the error is going to be something like

AttributeError: 'Model' object has no attribute 'a'

This kind of makes sense because indeed the Never fields never hold any value, but at the same time they are defined in the model, so it kind of makes sense as well to say that the instances do have those attributes. We should provide some better error messages, but before that gets handled in pydantic, I think in core we can return PydanticUndefined as a placeholder.

Serialisation

Serialising the never fields themselves will trigger an error. For instance,

v = RootModel[Never]()
v.model_dump()  # TypeError: type `never` cannot be serialized

On the other hand, serialising models containing never fields should work and the never fields should be omitted:

class Model(BaseModel):
    a: Never

assert Model().model_dump() == {}

These are covered by the new test cases included in this PR.

Manual integration test

Tested locally with the counterpart implementation for pydantic and it worked.

Related issue number

Part of pydantic/pydantic#9731

Checklist

  • Unit tests for the changes exist
  • Documentation reflects the changes where applicable
  • Pydantic tests pass with this pydantic-core (except for expected changes)
  • My PR is ready to review, please add a comment including the phrase "please review" to assign reviewers

Selected Reviewer: @sydney-runkle

Copy link

codspeed-hq bot commented Dec 10, 2024

CodSpeed Performance Report

Merging #1579 will not alter performance

Comparing changhc:9731-never (26df7ba) with main (6a455fb)

Summary

✅ 155 untouched benchmarks

Copy link

codecov bot commented Dec 10, 2024

Codecov Report

Attention: Patch coverage is 92.50000% with 6 lines in your changes missing coverage. Please review.

Project coverage is 89.64%. Comparing base (ab503cb) to head (26df7ba).
Report is 253 commits behind head on main.

Files with missing lines Patch % Lines
src/serializers/type_serializers/never.rs 81.25% 6 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1579      +/-   ##
==========================================
- Coverage   90.21%   89.64%   -0.57%     
==========================================
  Files         106      114       +8     
  Lines       16339    17980    +1641     
  Branches       36       40       +4     
==========================================
+ Hits        14740    16118    +1378     
- Misses       1592     1842     +250     
- Partials        7       20      +13     
Files with missing lines Coverage Δ
python/pydantic_core/core_schema.py 94.88% <100.00%> (+0.11%) ⬆️
src/errors/types.rs 99.45% <100.00%> (+0.01%) ⬆️
src/serializers/shared.rs 79.36% <100.00%> (+0.15%) ⬆️
src/serializers/type_serializers/model.rs 94.25% <100.00%> (+0.37%) ⬆️
src/validators/mod.rs 96.23% <100.00%> (+0.20%) ⬆️
src/validators/never.rs 100.00% <100.00%> (ø)
src/serializers/type_serializers/never.rs 81.25% <81.25%> (ø)

... and 51 files with indirect coverage changes


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 4c02cbd...26df7ba. Read the comment docs.

@changhc changhc marked this pull request as ready for review December 11, 2024 22:51
@changhc
Copy link
Contributor Author

changhc commented Dec 11, 2024

please review

@davidhewitt
Copy link
Contributor

@pydantic/oss would love your input on this design. I would have assumed a simpler design where any type containing a Never field (be it RootModel, BaseModel etc) would itself not be instantiable, because Never is not. Maybe there is some context I am missing.

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

Successfully merging this pull request may close these issues.

3 participants