|
1 | 1 | """Pre-allocation group models for test fixture generation.""" |
2 | 2 |
|
3 | 3 | import json |
| 4 | +from dataclasses import dataclass |
4 | 5 | from pathlib import Path |
5 | | -from typing import Any, Dict, Generator, Iterator, KeysView, List, Self, Tuple |
| 6 | +from typing import ( |
| 7 | + Any, |
| 8 | + Dict, |
| 9 | + Generator, |
| 10 | + Iterator, |
| 11 | + KeysView, |
| 12 | + List, |
| 13 | + Literal, |
| 14 | + Self, |
| 15 | + Tuple, |
| 16 | +) |
6 | 17 |
|
7 | 18 | from filelock import FileLock |
8 | 19 | from pydantic import Field, PrivateAttr |
@@ -155,13 +166,89 @@ def add_test_pre( |
155 | 166 | self.root[pre_alloc_hash] = group |
156 | 167 |
|
157 | 168 |
|
| 169 | +@dataclass(kw_only=True) |
| 170 | +class ModelDumpCache: |
| 171 | + """ |
| 172 | + Holds a cached dump of a model, the type of the cache (str or json) |
| 173 | + and the keyword arguments used to generate it. |
| 174 | + """ |
| 175 | + |
| 176 | + model_dump_config: Dict[str, Any] |
| 177 | + """Keyword arguments used to model dump the data.""" |
| 178 | + model_dump_mode: Literal["json", "python"] |
| 179 | + """Mode of the model dump when `model_dump` is called.""" |
| 180 | + model_dump_type: Literal["string", "dict"] |
| 181 | + """Whether `model_dump_json` or `model_dump` was used to generate the data.""" |
| 182 | + data: Any |
| 183 | + |
| 184 | + |
158 | 185 | class GroupPreAlloc(Alloc): |
| 186 | + """ |
| 187 | + Alloc that belongs to a pre-allocation group. |
| 188 | +
|
| 189 | + This is used to avoid re-calculating the state root for the pre-allocation |
| 190 | + group when it is accessed. |
| 191 | +
|
| 192 | + Also holds a cached model dump of the pre-allocation group, either in |
| 193 | + string or JSON format depending on the last request. |
| 194 | + """ |
| 195 | + |
159 | 196 | _pre_alloc_group: "PreAllocGroup" = PrivateAttr(init=False) |
| 197 | + _model_dump_cache: ModelDumpCache | None = PrivateAttr(None) |
| 198 | + _cache_miss_count: int = PrivateAttr(0) |
160 | 199 |
|
161 | 200 | def state_root(self) -> Hash: |
162 | 201 | """On pre-alloc groups, which are normally very big, we always cache.""" |
163 | 202 | return self._pre_alloc_group.genesis.state_root |
164 | 203 |
|
| 204 | + def model_dump( # type: ignore[override] |
| 205 | + self, mode: Literal["json", "python"], **kwargs: Any |
| 206 | + ) -> Any: |
| 207 | + """ |
| 208 | + Model dump the pre-allocation group, with caching. |
| 209 | +
|
| 210 | + Note: 'mode' here follows Pydantic's semantics: |
| 211 | + - 'python' -> standard model_dump |
| 212 | + - 'json' -> JSON-compatible python data |
| 213 | + """ |
| 214 | + if ( |
| 215 | + self._model_dump_cache is not None |
| 216 | + and self._model_dump_cache.model_dump_mode == mode |
| 217 | + and self._model_dump_cache.model_dump_type == "dict" |
| 218 | + and self._model_dump_cache.model_dump_config == kwargs |
| 219 | + ): |
| 220 | + return self._model_dump_cache.data |
| 221 | + |
| 222 | + self._cache_miss_count += 1 |
| 223 | + data = super().model_dump(mode=mode, **kwargs) |
| 224 | + self._model_dump_cache = ModelDumpCache( |
| 225 | + model_dump_mode=mode, |
| 226 | + model_dump_config=kwargs, |
| 227 | + model_dump_type="dict", |
| 228 | + data=data, |
| 229 | + ) |
| 230 | + return data |
| 231 | + |
| 232 | + def model_dump_json(self, **kwargs: Any) -> str: |
| 233 | + """Model dump the pre-allocation group in JSON string format, with caching.""" |
| 234 | + if ( |
| 235 | + self._model_dump_cache is not None |
| 236 | + and self._model_dump_cache.model_dump_mode == "json" |
| 237 | + and self._model_dump_cache.model_dump_type == "string" |
| 238 | + and self._model_dump_cache.model_dump_config == kwargs |
| 239 | + ): |
| 240 | + return self._model_dump_cache.data |
| 241 | + |
| 242 | + self._cache_miss_count += 1 |
| 243 | + data = super().model_dump_json(**kwargs) |
| 244 | + self._model_dump_cache = ModelDumpCache( |
| 245 | + model_dump_mode="json", |
| 246 | + model_dump_config=kwargs, |
| 247 | + model_dump_type="string", |
| 248 | + data=data, |
| 249 | + ) |
| 250 | + return data |
| 251 | + |
165 | 252 |
|
166 | 253 | class PreAllocGroup(PreAllocGroupBuilder): |
167 | 254 | """ |
|
0 commit comments