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

Pydantic V2 blog #4218

Merged
merged 25 commits into from Jul 10, 2022
Merged
Changes from 1 commit
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
5bdecf9
first draft of pydantic V2 blog
samuelcolvin Jul 6, 2022
5bb1ebb
more blog
samuelcolvin Jul 6, 2022
1296848
blog rendering and formatting
samuelcolvin Jul 6, 2022
1dd4ad7
more section
samuelcolvin Jul 6, 2022
3a77a57
completing conversion table
samuelcolvin Jul 6, 2022
8f6a9ef
prompt build
samuelcolvin Jul 6, 2022
eac0367
reviewing blog post
samuelcolvin Jul 6, 2022
24c4167
more reviewing and extending
samuelcolvin Jul 6, 2022
5bbea1f
recommendations from @Rabscuttler and @PrettyWood
samuelcolvin Jul 7, 2022
f0043eb
add implementation details and more suggestions
samuelcolvin Jul 7, 2022
022a008
comment about breaking changes
samuelcolvin Jul 7, 2022
c35c1df
convert namespae to table, more removals
samuelcolvin Jul 7, 2022
5d9988f
Apply suggestions from code review by @tiangolo
samuelcolvin Jul 7, 2022
ed6d7b1
feedback from @tiangolo's review
samuelcolvin Jul 7, 2022
1326ab5
changes from @adriangb's review
samuelcolvin Jul 7, 2022
83fe30c
Apply suggestions from code review
samuelcolvin Jul 8, 2022
a7bd04b
convert namespace info to psuedo-code
samuelcolvin Jul 8, 2022
be88158
rename property, remove schema_json()
samuelcolvin Jul 8, 2022
c8ba8f1
adding validation context
samuelcolvin Jul 8, 2022
f97b082
remove 'model_schema_json', take 2
samuelcolvin Jul 8, 2022
4acf85d
more tweaks while reviewing
samuelcolvin Jul 8, 2022
80ea6d7
comment about pypy and tagged unions
samuelcolvin Jul 8, 2022
c9c13dc
add thanks :prey:, prepare for release
samuelcolvin Jul 10, 2022
6551432
suggestions from @PrettyWood
samuelcolvin Jul 10, 2022
1808116
suggestions from @PrettyWood, model_dump_json comment
samuelcolvin Jul 10, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
57 changes: 48 additions & 9 deletions docs/blog/pydantic-v2.md
Expand Up @@ -319,7 +319,42 @@ translate it to Rust.
We should also add support for `validate_alias` and `dump_alias` as well as the standard `alias`
to allow for customising field keys.

### Model namespace cleanup :thumbsup:
### Validation Context :thumbsup:

Pydantic V2 will add a new optional `context` argument to `model_validate` and `model_validate_json`
which will allow you to pass information not available when creating a model to validators.
See [pydantic#1549](https://github.com/samuelcolvin/pydantic/issues/1549) for motivation.

```py title="Context during Validation"
from pydantic import BaseModel, EmailStr, validator

class User(BaseModel):
email: EmailStr
home_country: str

@validator('home_country')
def check_home_country(cls, v, context):
if v not in context['countries']:
raise ValueError('invalid country choice')
return v

async def add_user(post_data: bytes):
countries = set(await db_connection.fetch_all('select code from country'))
user = User.model_validate_json(post_data, context={'countries': countries})
...
```

!!! note
We (actually mostly Sebastián :wink:) will have to make some changes to FastAPI to fully leverage `context`
as we'd need some kind of dependency injection to build context before validation so models can still be passed as
arguments to views. I'm sure he'll be game.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm game! Haha 😅

I think it's gonna be challenging but I'm confident is solvable/doable.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, it's not like anything breaks here if you make no changes - just extra functionality if you do...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we might need to add another method to models like

class MyModel(BaseModel):
    @classmethod
    async def model_prepare_context(cls, db_conn: Depends(get_db)) -> dict[str, Any:
        """allows custom logic to prepare context"""

I guess model_prepare_context doesn't even need to on BaseModel, you just document in FastAPI that if it's defined, it'll be called with dependency resolution to prepare context?

Up to you, but I'm very happy to add something like this to pydantic if it helps FastAPI.


!!! warning
Although this will make it slightly easier to run synchronous IO (HTTP requests, DB. queries, etc.)
from within validators, I strongly advise you keep IO separate from validation - do it before and use context,
do it afterwards, avoid where possible making queries inside validation.

### Model Namespace Cleanup :thumbsup:

For years I've wanted to clean up the model namespace,
see [pydantic#1001](https://github.com/samuelcolvin/pydantic/issues/1001). This would avoid confusing gotchas when field
Expand All @@ -340,30 +375,32 @@ class BaseModel:
model_fields: List[FieldInfo]
"""previously `__fields__`, although the format will change a lot"""
@classmethod
def model_validate(cls, data: Any, *, context=None) -> Self:
def model_validate(cls, data: Any, *, context=None) -> Self: # (1)
"""
previously `parse_obj()`, validate data
"""
@classmethod
def model_validate_json(
cls,
data: str | bytes | bytearray,
*, context=None
*,
context=None
) -> Self:
"""
previously `parse_raw(..., content_type='json')`
previously `parse_raw(..., content_type='application/json')`
validate data from JSON
"""
@classmethod
def model_is_instance(cls, data: Any, *, context=None) -> bool:
def model_is_instance(cls, data: Any, *, context=None) -> bool: # (2)
"""
new, check if data is value for the model
""" # (2)
"""
@classmethod
def model_is_instance_json(
cls,
data: str | bytes | bytearray,
*, context=None
*,
context=None
) -> bool:
"""
Same as `model_is_instance`, but from JSON
Expand Down Expand Up @@ -431,7 +468,7 @@ class BaseModel:
"""
```

1. see [Implementation Details below](#implementation-details)
1. see [Validation Context](#validation-context) for more information on `context`
2. see [`is_instance` checks](#is_instance-like-checks)

The following methods will be removed:
Expand Down Expand Up @@ -511,6 +548,8 @@ pydantic-core will provide binaries in PyPI for (at least):
compiled for wasm32 using emscripten and unit tests pass, except where cpython itself has
[problems](https://github.com/pyodide/pyodide/issues/2841))

Binaries for pypy should also be possible, TODO.

Other binaries can be added provided they can be (cross-)compiled on github actions.
If no binary is available from PyPI, pydantic-core can be compiled from source if Rust stable is available.
samuelcolvin marked this conversation as resolved.
Show resolved Hide resolved

Expand Down Expand Up @@ -567,7 +606,7 @@ It's time to stop fighting that, and use consistent names.
The word "parse" will no longer be used except when talking about JSON parsing, see
[model methods](#model-namespace-cleanup) above.

## Changes to custom field types :neutral_face:
### Changes to custom field types :neutral_face:

Since the core structure of validators has changed from "a list of validators to call one after another" to
"a tree of validators which call each other", the
Expand Down