From e9cdebb73e38e4447160f28f6d76bfd092ed1aa4 Mon Sep 17 00:00:00 2001 From: Vittoria Date: Sun, 3 May 2026 03:00:00 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9A=A1=20Skip=20set(obj.keys())=20allocation?= =?UTF-8?q?=20in=20jsonable=5Fencoder=20when=20include/exclude=20are=20not?= =?UTF-8?q?=20set?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fastapi/encoders.py | 14 +++++++------ tests/test_jsonable_encoder.py | 38 ++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/fastapi/encoders.py b/fastapi/encoders.py index 43f24101b6..329f96ace2 100644 --- a/fastapi/encoders.py +++ b/fastapi/encoders.py @@ -280,11 +280,13 @@ def jsonable_encoder( return None if isinstance(obj, dict): encoded_dict = {} - allowed_keys = set(obj.keys()) - if include is not None: - allowed_keys &= set(include) - if exclude is not None: - allowed_keys -= set(exclude) + allowed_keys: set[Any] | None = None + if include is not None or exclude is not None: + allowed_keys = set(obj.keys()) + if include is not None: + allowed_keys &= set(include) + if exclude is not None: + allowed_keys -= set(exclude) for key, value in obj.items(): if ( ( @@ -293,7 +295,7 @@ def jsonable_encoder( or (not key.startswith("_sa")) ) and (value is not None or not exclude_none) - and key in allowed_keys + and (allowed_keys is None or key in allowed_keys) ): encoded_key = jsonable_encoder( key, diff --git a/tests/test_jsonable_encoder.py b/tests/test_jsonable_encoder.py index c23a9e5d79..dde6fe3f8e 100644 --- a/tests/test_jsonable_encoder.py +++ b/tests/test_jsonable_encoder.py @@ -329,3 +329,41 @@ def test_encode_color(module_path): data = {"color": Color("blue")} assert jsonable_encoder(data) == {"color": "blue"} + + +def test_dict_no_filter_returns_all_keys(): + result = jsonable_encoder({"a": 1, "b": 2, "c": 3}) + assert result == {"a": 1, "b": 2, "c": 3} + + +def test_dict_include_filters_correctly(): + result = jsonable_encoder({"a": 1, "b": 2}, include={"a"}) + assert result == {"a": 1} + + +def test_dict_exclude_filters_correctly(): + result = jsonable_encoder({"a": 1, "b": 2}, exclude={"b"}) + assert result == {"a": 1} + + +def test_dict_empty_include_returns_empty(): + result = jsonable_encoder({"a": 1}, include=set()) + assert result == {} + + +def test_dict_empty_exclude_returns_all(): + result = jsonable_encoder({"a": 1}, exclude=set()) + assert result == {"a": 1} + + +def test_dict_both_include_and_exclude(): + result = jsonable_encoder( + {"a": 1, "b": 2, "c": 3}, include={"a", "b"}, exclude={"b"} + ) + assert result == {"a": 1} + + +def test_encode_nested_dict(): + nested = {"level1": {"level2": {"level3": 42}}} + result = jsonable_encoder(nested) + assert result == nested