Skip to content

Commit b5b4035

Browse files
committed
Use pickle
1 parent fdfa22f commit b5b4035

File tree

2 files changed

+14
-20
lines changed

2 files changed

+14
-20
lines changed

src/_pytest/subtests.py

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from contextlib import ExitStack
1212
from contextlib import nullcontext
1313
import dataclasses
14-
import json
14+
import pickle
1515
import time
1616
from types import TracebackType
1717
from typing import Any
@@ -64,24 +64,15 @@ class SubtestContext:
6464

6565
def _to_json(self) -> dict[str, Any]:
6666
result = dataclasses.asdict(self)
67-
68-
# Best-effort to convert the kwargs values to JSON (pytest-dev/pytest-xdist#1273).
69-
# If they can be converted, we return as it is, otherwise we return its saferepr because it seems
70-
# this is the best we can do at this point.
71-
def convert(x: Any) -> Any:
72-
try:
73-
json.dumps(x)
74-
except TypeError:
75-
return saferepr(x)
76-
else:
77-
return x
78-
79-
result["kwargs"] = {k: convert(v) for (k, v) in result["kwargs"].items()}
67+
# Use protocol 0 because it is human-readable and guaranteed to be not-binary.
68+
protocol = 0
69+
data = pickle.dumps(result["kwargs"], protocol=protocol)
70+
result["kwargs"] = data.decode("UTF-8")
8071
return result
8172

8273
@classmethod
8374
def _from_json(cls, d: dict[str, Any]) -> Self:
84-
return cls(msg=d["msg"], kwargs=d["kwargs"])
75+
return cls(msg=d["msg"], kwargs=pickle.loads(d["kwargs"].encode("UTF-8")))
8576

8677

8778
@dataclasses.dataclass(init=False)

testing/test_subtests.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import sys
66
from typing import Literal
77

8-
from _pytest._io.saferepr import saferepr
98
from _pytest.subtests import SubtestContext
109
from _pytest.subtests import SubtestReport
1110
import pytest
@@ -960,14 +959,17 @@ def test(subtests):
960959
)
961960

962961

962+
class MyEnum(Enum):
963+
"""Used in test_serialization, needs to be declared at the module level to be pickled."""
964+
965+
A = "A"
966+
967+
963968
def test_serialization() -> None:
964969
"""Ensure subtest's kwargs are serialized using `saferepr` (pytest-dev/pytest-xdist#1273)."""
965970
from _pytest.subtests import pytest_report_from_serializable
966971
from _pytest.subtests import pytest_report_to_serializable
967972

968-
class MyEnum(Enum):
969-
A = "A"
970-
971973
report = SubtestReport(
972974
"test_foo::test_foo",
973975
("test_foo.py", 12, ""),
@@ -984,7 +986,7 @@ class MyEnum(Enum):
984986
new_report = pytest_report_from_serializable(data)
985987
assert new_report is not None
986988
assert new_report.context == SubtestContext(
987-
msg="custom message", kwargs=dict(i=10, a=saferepr(MyEnum.A))
989+
msg="custom message", kwargs=dict(i=10, a=MyEnum.A)
988990
)
989991

990992

@@ -1010,5 +1012,6 @@ def test(self):
10101012
pass
10111013
"""
10121014
)
1015+
pytester.syspathinsert()
10131016
result = pytester.runpytest("-n1", "-pxdist.plugin")
10141017
result.assert_outcomes(passed=2)

0 commit comments

Comments
 (0)