Skip to content

Commit 862e925

Browse files
Евгений БлиновЕвгений Блинов
authored andcommitted
Refactor to_json/from_json to use TypedDict for schema validation
1 parent 2d4d682 commit 862e925

1 file changed

Lines changed: 38 additions & 17 deletions

File tree

microbenchmark/benchmark_result.py

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,24 @@
44
import math
55
from dataclasses import dataclass, field
66
from functools import cached_property
7-
from typing import TYPE_CHECKING, Any
7+
from typing import TYPE_CHECKING, TypedDict
88

99
if TYPE_CHECKING:
1010
from microbenchmark.scenario import Scenario
1111

1212

13+
class _ScenarioMeta(TypedDict):
14+
name: str
15+
doc: str
16+
number: int
17+
18+
19+
class _ResultJson(TypedDict):
20+
durations: list[float]
21+
is_primary: bool
22+
scenario: _ScenarioMeta | None
23+
24+
1325
@dataclass
1426
class BenchmarkResult:
1527
scenario: Scenario | None
@@ -45,28 +57,37 @@ def p99(self) -> BenchmarkResult:
4557
return self.percentile(99)
4658

4759
def to_json(self) -> str:
48-
scenario_data: dict[str, Any] | None
60+
scenario_meta: _ScenarioMeta | None
4961
if self.scenario is not None:
50-
scenario_data = {
51-
'name': self.scenario.name,
52-
'doc': self.scenario.doc,
53-
'number': self.scenario.number,
54-
}
62+
scenario_meta = _ScenarioMeta(
63+
name=self.scenario.name,
64+
doc=self.scenario.doc,
65+
number=self.scenario.number,
66+
)
5567
else:
56-
scenario_data = None
57-
return json.dumps({
58-
'durations': list(self.durations),
59-
'is_primary': self.is_primary,
60-
'scenario': scenario_data,
61-
})
68+
scenario_meta = None
69+
data: _ResultJson = _ResultJson(
70+
durations=list(self.durations),
71+
is_primary=self.is_primary,
72+
scenario=scenario_meta,
73+
)
74+
return json.dumps(data)
6275

6376
@classmethod
6477
def from_json(cls, data: str) -> BenchmarkResult:
65-
parsed = json.loads(data)
66-
if 'durations' not in parsed or 'is_primary' not in parsed:
78+
raw: object = json.loads(data)
79+
if not isinstance(raw, dict):
80+
raise ValueError('JSON must be an object')
81+
if 'durations' not in raw or 'is_primary' not in raw:
6782
raise ValueError('JSON is missing required fields: durations, is_primary')
83+
raw_durations = raw['durations']
84+
raw_is_primary = raw['is_primary']
85+
if not isinstance(raw_durations, list):
86+
raise ValueError('durations must be a list')
87+
if not isinstance(raw_is_primary, bool):
88+
raise ValueError('is_primary must be a bool')
6889
return cls(
6990
scenario=None,
70-
durations=tuple(float(d) for d in parsed['durations']),
71-
is_primary=bool(parsed['is_primary']),
91+
durations=tuple(float(d) for d in raw_durations),
92+
is_primary=raw_is_primary,
7293
)

0 commit comments

Comments
 (0)