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 unpacked TypedDict to type hint variadic keyword arguments in ArgumentsValidator #1451

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

Conversation

Viicos
Copy link
Member

@Viicos Viicos commented Sep 13, 2024

Change Summary

Part of pydantic/pydantic#9619.

Related issue number

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

src/validators/var_kwargs.rs Outdated Show resolved Hide resolved
Copy link

codspeed-hq bot commented Sep 16, 2024

CodSpeed Performance Report

Merging #1451 will not alter performance

Comparing kwargs-td (b9dbb34) with main (bc0c97a)

Summary

✅ 155 untouched benchmarks

None => None,
};

if var_kwargs_mode == VarKwargsMode::UnpackedTypedDict && var_kwargs_validator.is_none() {
Copy link
Member Author

Choose a reason for hiding this comment

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

I'm wondering if we should also check that var_kwargs_validator is a TypedDictValidator?

Copy link
Member

Choose a reason for hiding this comment

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

I don't think you need to, given that you have the conditional checks in pydantic.

Copy link
Contributor

Choose a reason for hiding this comment

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

Making it a TypedDictValdiator statically (at build time) would allow for efficiency gains (by avoiding the dispatch via CombinedValidator).

But I wonder, are there cases where it can be wrapped in a function-after validator (e.g. model_validator)?

Copy link
Member Author

Choose a reason for hiding this comment

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

Making it a TypedDictValdiator statically (at build time) would allow for efficiency gains (by avoiding the dispatch via CombinedValidator).

The thing is (as described here) var_kwargs_validator is used for both uniform and unpacked-typed-dict modes.

But I wonder, are there cases where it can be wrapped in a function-after validator (e.g. model_validator)?

only config can be attached to typed dicts iirc, and it still results in a typed dict schema.

Copy link
Contributor

Choose a reason for hiding this comment

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

You could have

#[derive(Debug, PartialEq)]
enum VarKwargsMode {
    Uniform(CombinedValidator),
    UnpackedTypedDict(TypedDictValidator),
}

... and replace the FromStr implementation with a bespoke function like from_string_and_validator or similar.

src/validators/arguments.rs Outdated Show resolved Hide resolved
@Viicos Viicos changed the title Add support for TypedDict for **kwargs Add support for unpacked TypedDict to type hint variadic keyword arguments with @validate_call Sep 17, 2024
@Viicos Viicos changed the title Add support for unpacked TypedDict to type hint variadic keyword arguments with @validate_call Add support for unpacked TypedDict to type hint variadic keyword arguments in the ArgumentsValidator Sep 17, 2024
class ArgumentsSchema(TypedDict, total=False):
type: Required[Literal['arguments']]
arguments_schema: Required[List[ArgumentsParameter]]
populate_by_name: bool
var_args_schema: CoreSchema
var_kwargs_mode: VarKwargsMode
Copy link
Member Author

Choose a reason for hiding this comment

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

As discussed with DH, we decided to have everything coupled together in the ArgumentsSchema, as having a single VarKwargsSchema did not really make sense and made things harder to handle in pydantic core.

This has the downside that var_kwargs_schema serves two purposes, depending on var_kwargs_mode: a core schema to validate every value of each extra kwarg, or a TypedDictSchema to validate kwargs entirely. Maybe we could make them two separate keys?

Copy link
Member

Choose a reason for hiding this comment

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

Maybe we could make them two separate keys?

WDYM by this?

I'm alright with this as it stands now.

Copy link
Member Author

Choose a reason for hiding this comment

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

WDYM by this?

if var_kwargs_mode is 'single', then var_kwargs_single_schema would have to be provided. Otherwise if var_kwargs_mode is 'unpacked-typed-dict, var_kwargs_unpacked_typed_dict_schema would have to be provided. This makes things more explicit but with more validation logic involved so probably best to keep it as is.

@Viicos Viicos changed the title Add support for unpacked TypedDict to type hint variadic keyword arguments in the ArgumentsValidator Add support for unpacked TypedDict to type hint variadic keyword arguments in ArgumentsValidator Sep 17, 2024
@Viicos Viicos marked this pull request as ready for review September 17, 2024 13:06
Copy link
Member

@sydney-runkle sydney-runkle left a comment

Choose a reason for hiding this comment

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

Looking great thus far! A couple of rust syntax suggestions + potentially one constant change.

class ArgumentsSchema(TypedDict, total=False):
type: Required[Literal['arguments']]
arguments_schema: Required[List[ArgumentsParameter]]
populate_by_name: bool
var_args_schema: CoreSchema
var_kwargs_mode: VarKwargsMode
Copy link
Member

Choose a reason for hiding this comment

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

Maybe we could make them two separate keys?

WDYM by this?

I'm alright with this as it stands now.

Comment on lines 3422 to 3424
var_kwargs_mode: The validation mode to use for variadic keyword arguments. If `'single'`, every value of the
keyword arguments will be validated against the `var_kwargs_schema` schema. If `'unpacked-typed-dict'`,
the `schema` argument must be a [`typed_dict_schema`][pydantic_core.core_schema.typed_dict_schema]
Copy link
Member

Choose a reason for hiding this comment

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

What if instead of single we did uniform? Don't want to bikeshed here too much, but I was a bit confused by single on its own.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes I'm not too happy with name either. uniform seems better, although there might be an even more explicit name, I'll think about it.

Copy link
Contributor

Choose a reason for hiding this comment

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

uniform seems good to me 👍

Copy link
Contributor

Choose a reason for hiding this comment

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

I wonder about whether to handle uniform via the "extras" of the typed dict schema (if such a thing exists) and have simpler code here (i.e. no need for mode, just always require typed dict schema). Maybe a little breaking, though?

Copy link
Member Author

Choose a reason for hiding this comment

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

There's a extras_schema key in the TypedDictSchema, but it is not used currently. For Pydantic models, we support:

class Model(BaseModel):
    __pydantic_extra__: dict[str, int]

But we don't for typed dicts. I believe it's best to wait for https://peps.python.org/pep-0728/, this will probably completely change how we handle extra keys for typed dicts currently.

None => None,
};

if var_kwargs_mode == VarKwargsMode::UnpackedTypedDict && var_kwargs_validator.is_none() {
Copy link
Member

Choose a reason for hiding this comment

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

I don't think you need to, given that you have the conditional checks in pydantic.

src/validators/arguments.rs Outdated Show resolved Hide resolved
src/validators/arguments.rs Outdated Show resolved Hide resolved
src/validators/arguments.rs Show resolved Hide resolved
src/validators/arguments.rs Show resolved Hide resolved
Co-authored-by: Sydney Runkle <54324534+sydney-runkle@users.noreply.github.com>
Copy link
Contributor

@davidhewitt davidhewitt left a comment

Choose a reason for hiding this comment

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

Overall LGTM with some brief thoughts...

Comment on lines 3422 to 3424
var_kwargs_mode: The validation mode to use for variadic keyword arguments. If `'single'`, every value of the
keyword arguments will be validated against the `var_kwargs_schema` schema. If `'unpacked-typed-dict'`,
the `schema` argument must be a [`typed_dict_schema`][pydantic_core.core_schema.typed_dict_schema]
Copy link
Contributor

Choose a reason for hiding this comment

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

uniform seems good to me 👍

src/validators/arguments.rs Show resolved Hide resolved
None => None,
};

if var_kwargs_mode == VarKwargsMode::UnpackedTypedDict && var_kwargs_validator.is_none() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Making it a TypedDictValdiator statically (at build time) would allow for efficiency gains (by avoiding the dispatch via CombinedValidator).

But I wonder, are there cases where it can be wrapped in a function-after validator (e.g. model_validator)?

src/validators/arguments.rs Outdated Show resolved Hide resolved
src/validators/arguments.rs Outdated Show resolved Hide resolved
Comment on lines 3422 to 3424
var_kwargs_mode: The validation mode to use for variadic keyword arguments. If `'single'`, every value of the
keyword arguments will be validated against the `var_kwargs_schema` schema. If `'unpacked-typed-dict'`,
the `schema` argument must be a [`typed_dict_schema`][pydantic_core.core_schema.typed_dict_schema]
Copy link
Contributor

Choose a reason for hiding this comment

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

I wonder about whether to handle uniform via the "extras" of the typed dict schema (if such a thing exists) and have simpler code here (i.e. no need for mode, just always require typed dict schema). Maybe a little breaking, though?

Co-authored-by: David Hewitt <david.hewitt@pydantic.dev>
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