Skip to content

support __pydantic_extra__ when serializing #576

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

Merged
merged 11 commits into from
May 4, 2023
6 changes: 5 additions & 1 deletion pydantic_core/core_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class CoreConfig(TypedDict, total=False):
config_choose_priority: int
# if configs are merged, which should take precedence, default 0, default means child takes precedence
config_merge_priority: int
# settings related to typed_dicts only
# settings related to typed dicts, model fields, dataclass fields
extra_fields_behavior: ExtraBehavior
typed_dict_total: bool # default: True
# used on typed-dicts and tagged union keys
Expand Down Expand Up @@ -2841,6 +2841,7 @@ class ModelSchema(TypedDict, total=False):
revalidate_instances: Literal['always', 'never', 'subclass-instances'] # default: 'never'
strict: bool
frozen: bool
extra_behavior: ExtraBehavior
config: CoreConfig
ref: str
metadata: Any
Expand All @@ -2855,6 +2856,7 @@ def model_schema(
revalidate_instances: Literal['always', 'never', 'subclass-instances'] | None = None,
strict: bool | None = None,
frozen: bool | None = None,
extra_behavior: ExtraBehavior | None = None,
config: CoreConfig | None = None,
ref: str | None = None,
metadata: Any = None,
Expand Down Expand Up @@ -2894,6 +2896,7 @@ class MyModel:
should re-validate defaults to config.revalidate_instances, else 'never'
strict: Whether the model is strict
frozen: Whether the model is frozen
extra_behavior: The extra behavior to use for the model, used in serialization
config: The config to use for the model
ref: optional unique identifier of the schema, used to reference the schema in other places
metadata: Any other information you want to include with the schema, not used by pydantic-core
Expand All @@ -2907,6 +2910,7 @@ class MyModel:
revalidate_instances=revalidate_instances,
strict=strict,
frozen=frozen,
extra_behavior=extra_behavior,
config=config,
ref=ref,
metadata=metadata,
Expand Down
41 changes: 41 additions & 0 deletions src/build_tools.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::borrow::Cow;
use std::cmp::Ordering;
use std::error::Error;
use std::fmt;

Expand Down Expand Up @@ -280,3 +281,43 @@ impl ExtraBehavior {
Ok(res)
}
}

pub(crate) fn build_model_config<'a>(
py: Python<'a>,
schema: &'a PyDict,
parent_config: Option<&'a PyDict>,
) -> PyResult<Option<&'a PyDict>> {
let child_config: Option<&PyDict> = schema.get_as(intern!(py, "config"))?;
match (parent_config, child_config) {
(Some(parent), None) => Ok(Some(parent)),
(None, Some(child)) => Ok(Some(child)),
(None, None) => Ok(None),
(Some(parent), Some(child)) => {
let key = intern!(py, "config_choose_priority");
let parent_choose: i32 = parent.get_as(key)?.unwrap_or_default();
let child_choose: i32 = child.get_as(key)?.unwrap_or_default();
match parent_choose.cmp(&child_choose) {
Ordering::Greater => Ok(Some(parent)),
Ordering::Less => Ok(Some(child)),
Ordering::Equal => {
let key = intern!(py, "config_merge_priority");
let parent_merge: i32 = parent.get_as(key)?.unwrap_or_default();
let child_merge: i32 = child.get_as(key)?.unwrap_or_default();
match parent_merge.cmp(&child_merge) {
Ordering::Greater => {
let new_child = child.copy()?;
new_child.update(parent.as_mapping())?;
Ok(Some(new_child))
}
// otherwise child is the winner
_ => {
let new_parent = parent.copy()?;
new_parent.update(child.as_mapping())?;
Ok(Some(new_parent))
}
}
}
}
}
}
}
Loading