Skip to content

allow sorting keys on to_json and to_python by passing in sort_keys #1637

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

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions python/pydantic_core/_pydantic_core.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@ class SchemaSerializer:
exclude_defaults: bool = False,
exclude_none: bool = False,
round_trip: bool = False,
sort_keys: bool = False,
warnings: bool | Literal['none', 'warn', 'error'] = True,
fallback: Callable[[Any], Any] | None = None,
serialize_as_any: bool = False,
Expand All @@ -326,6 +327,7 @@ class SchemaSerializer:
exclude_defaults: Whether to exclude fields that are equal to their default value.
exclude_none: Whether to exclude fields that have a value of `None`.
round_trip: Whether to enable serialization and validation round-trip support.
sort_keys: Whether to sort dictionary keys. If True, all dictionary keys will be sorted alphabetically, including nested dictionaries.
warnings: How to handle invalid fields. False/"none" ignores them, True/"warn" logs errors,
"error" raises a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError].
fallback: A function to call when an unknown value is encountered,
Expand All @@ -352,6 +354,7 @@ class SchemaSerializer:
exclude_defaults: bool = False,
exclude_none: bool = False,
round_trip: bool = False,
sort_keys: bool = False,
warnings: bool | Literal['none', 'warn', 'error'] = True,
fallback: Callable[[Any], Any] | None = None,
serialize_as_any: bool = False,
Expand All @@ -371,6 +374,7 @@ class SchemaSerializer:
exclude_defaults: Whether to exclude fields that are equal to their default value.
exclude_none: Whether to exclude fields that have a value of `None`.
round_trip: Whether to enable serialization and validation round-trip support.
sort_keys: Whether to sort dictionary keys. If True, all dictionary keys will be sorted alphabetically, including nested dictionaries.
warnings: How to handle invalid fields. False/"none" ignores them, True/"warn" logs errors,
"error" raises a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError].
fallback: A function to call when an unknown value is encountered,
Expand Down Expand Up @@ -398,6 +402,7 @@ def to_json(
by_alias: bool = True,
exclude_none: bool = False,
round_trip: bool = False,
sort_keys: bool = False,
timedelta_mode: Literal['iso8601', 'float'] = 'iso8601',
bytes_mode: Literal['utf8', 'base64', 'hex'] = 'utf8',
inf_nan_mode: Literal['null', 'constants', 'strings'] = 'constants',
Expand All @@ -419,6 +424,7 @@ def to_json(
by_alias: Whether to use the alias names of fields.
exclude_none: Whether to exclude fields that have a value of `None`.
round_trip: Whether to enable serialization and validation round-trip support.
sort_keys: Whether to sort dictionary keys. If True, all dictionary keys will be sorted alphabetically, including nested dictionaries.
timedelta_mode: How to serialize `timedelta` objects, either `'iso8601'` or `'float'`.
bytes_mode: How to serialize `bytes` objects, either `'utf8'`, `'base64'`, or `'hex'`.
inf_nan_mode: How to serialize `Infinity`, `-Infinity` and `NaN` values, either `'null'`, `'constants'`, or `'strings'`.
Expand Down Expand Up @@ -477,6 +483,7 @@ def to_jsonable_python(
by_alias: bool = True,
exclude_none: bool = False,
round_trip: bool = False,
sort_keys: bool = False,
timedelta_mode: Literal['iso8601', 'float'] = 'iso8601',
bytes_mode: Literal['utf8', 'base64', 'hex'] = 'utf8',
inf_nan_mode: Literal['null', 'constants', 'strings'] = 'constants',
Expand All @@ -498,6 +505,7 @@ def to_jsonable_python(
by_alias: Whether to use the alias names of fields.
exclude_none: Whether to exclude fields that have a value of `None`.
round_trip: Whether to enable serialization and validation round-trip support.
sort_keys: Whether to sort dictionary keys. If True, all dictionary keys will be sorted alphabetically, including nested dictionaries.
timedelta_mode: How to serialize `timedelta` objects, either `'iso8601'` or `'float'`.
bytes_mode: How to serialize `bytes` objects, either `'utf8'`, `'base64'`, or `'hex'`.
inf_nan_mode: How to serialize `Infinity`, `-Infinity` and `NaN` values, either `'null'`, `'constants'`, or `'strings'`.
Expand Down
3 changes: 3 additions & 0 deletions python/pydantic_core/core_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,9 @@ def serialize_as_any(self) -> bool: ...
@property
def round_trip(self) -> bool: ...

@property
def sort_keys(self) -> bool: ...

def mode_is_json(self) -> bool: ...

def __str__(self) -> str: ...
Expand Down
1 change: 1 addition & 0 deletions src/errors/validation_exception.rs
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,7 @@ impl ValidationError {
None,
false,
false,
false,
true,
Comment on lines 348 to 351
Copy link
Member

Choose a reason for hiding this comment

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

@davidhewitt this is getting gross 😢

None,
DuckTypingSerMode::SchemaBased,
Expand Down
8 changes: 8 additions & 0 deletions src/serializers/extra.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ impl SerializationState {
by_alias: Option<bool>,
exclude_none: bool,
round_trip: bool,
sort_keys: bool,
serialize_unknown: bool,
fallback: Option<&'py Bound<'_, PyAny>>,
duck_typing_ser_mode: DuckTypingSerMode,
Expand All @@ -100,6 +101,7 @@ impl SerializationState {
false,
exclude_none,
round_trip,
sort_keys,
&self.config,
&self.rec_guard,
serialize_unknown,
Expand All @@ -126,6 +128,7 @@ pub(crate) struct Extra<'a> {
pub exclude_defaults: bool,
pub exclude_none: bool,
pub round_trip: bool,
pub sort_keys: bool,
pub config: &'a SerializationConfig,
pub rec_guard: &'a SerRecursionState,
// the next two are used for union logic
Expand All @@ -152,6 +155,7 @@ impl<'a> Extra<'a> {
exclude_defaults: bool,
exclude_none: bool,
round_trip: bool,
sort_keys: bool,
config: &'a SerializationConfig,
rec_guard: &'a SerRecursionState,
serialize_unknown: bool,
Expand All @@ -168,6 +172,7 @@ impl<'a> Extra<'a> {
exclude_defaults,
exclude_none,
round_trip,
sort_keys,
config,
rec_guard,
check: SerCheck::None,
Expand Down Expand Up @@ -236,6 +241,7 @@ pub(crate) struct ExtraOwned {
exclude_defaults: bool,
exclude_none: bool,
round_trip: bool,
sort_keys: bool,
config: SerializationConfig,
rec_guard: SerRecursionState,
check: SerCheck,
Expand All @@ -257,6 +263,7 @@ impl ExtraOwned {
exclude_defaults: extra.exclude_defaults,
exclude_none: extra.exclude_none,
round_trip: extra.round_trip,
sort_keys: extra.sort_keys,
config: extra.config.clone(),
rec_guard: extra.rec_guard.clone(),
check: extra.check,
Expand All @@ -279,6 +286,7 @@ impl ExtraOwned {
exclude_defaults: self.exclude_defaults,
exclude_none: self.exclude_none,
round_trip: self.round_trip,
sort_keys: self.sort_keys,
config: &self.config,
rec_guard: &self.rec_guard,
check: self.check,
Expand Down
Loading
Loading