Skip to content
Merged
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
11 changes: 10 additions & 1 deletion src/oold/model/v1/_descriptor.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

from __future__ import annotations

import inspect
import json
from typing import Any, TypeVar, overload

Expand All @@ -36,6 +37,9 @@

_MANY_SHAPES = {SHAPE_LIST, SHAPE_SET, SHAPE_TUPLE}

_DICT_KWARGS = frozenset(inspect.signature(BaseModel.dict).parameters) - {"self"}
"""The arguments ``BaseModel.dict`` accepts, which ``json`` has to route to it."""

_M = TypeVar("_M")

_TYPE_REGISTRY: dict[str, type] = {}
Expand Down Expand Up @@ -345,7 +349,12 @@ def json(self, **kwargs: Any) -> str:
# rejects them.
encoder = kwargs.pop("encoder", None) or self.__json_encoder__
kwargs.pop("models_as_dict", None)
return json.dumps(self.dict(**kwargs), default=encoder)
# pydantic v1 names the dict() arguments explicitly and collects the
# rest into **dumps_kwargs. Anything not selecting data - indent,
# sort_keys, separators - belongs to json.dumps, and dict() raises
# TypeError on it.
dumps_kwargs = {key: kwargs.pop(key) for key in list(kwargs) if key not in _DICT_KWARGS}
return json.dumps(self.dict(**kwargs), default=encoder, **dumps_kwargs)

def to_json(self, exclude_defaults: bool = False) -> dict[str, Any]:
return json.loads(self.json(exclude_none=True, exclude_defaults=exclude_defaults))
Expand Down
14 changes: 14 additions & 0 deletions tests/test_compat_parity_v1.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,20 @@ def probe(tag, T, M):
assert shipped == auto


def test_json_passes_dumps_kwargs_to_json_dumps():
"""pydantic v1 splits json()'s arguments: the dict() ones select the data,
the rest go to json.dumps. Routing all of them to dict() raises TypeError on
indent, sort_keys and separators, which are valid pydantic v1 calls."""

def probe(tag, T, M):
m = M(id="ex:m", title="x", links=[f"ex:{tag}1", f"ex:{tag}2"], one=f"ex:{tag}1")
return m.json(exclude_none=True, indent=2, sort_keys=True, separators=(",", ": "))

shipped, auto = collect(probe)
assert "\n " in auto, f"indent never reached json.dumps: {auto!r}"
assert shipped == auto


def test_raw_dict_lists_every_field():
def probe(tag, T, M):
m = M(id="ex:m", title="x", one=f"ex:{tag}1")
Expand Down
Loading