| 147 | |
| 148 | @dataclass |
| 149 | class Cache: |
| 150 | defs: dict[Name, Any] |
| 151 | hash: str |
| 152 | cache_type: CacheType |
| 153 | stateful_refs: set[str] |
| 154 | hit: bool |
| 155 | # meta corresponds to internally used data, kept as a dictionary to allow |
| 156 | # for backwards pickle compatibility with future entries. |
| 157 | # TODO: Utilize to store code and output in cache. |
| 158 | # TODO: Consider storing graph information such that execution history can |
| 159 | # be explored and visualized. |
| 160 | meta: dict[MetaKey, Any] |
| 161 | |
| 162 | def restore(self, scope: dict[str, Any]) -> None: |
| 163 | """Restores values from cache, into scope.""" |
| 164 | memo: dict[int, Any] = {} # Track processed objects to handle cycles |
| 165 | for var, lookup in self._restore_order(self.contextual_defs()): |
| 166 | value = self.defs.get(var, None) |
| 167 | scope[lookup] = self._restore_from_stub_if_needed( |
| 168 | value, scope, memo |
| 169 | ) |
| 170 | |
| 171 | for key, value in self.meta.items(): |
| 172 | self.meta[key] = self._restore_from_stub_if_needed( |
| 173 | value, scope, memo |
| 174 | ) |
| 175 | |
| 176 | defs = {**globals(), **scope} |
| 177 | for ref in self.stateful_refs: |
| 178 | if ref not in defs: |
| 179 | raise CacheException( |
| 180 | "Failure while restoring cached values. " |
| 181 | "Cache expected a reference to a " |
| 182 | f"variable that is not present ({ref})." |
| 183 | ) |
| 184 | value = defs[ref] |
| 185 | if isinstance(value, SetFunctor): |
| 186 | value(self.defs[ref]) |
| 187 | # UI Values cannot be easily programmatically set, so only update |
| 188 | # state values. |
| 189 | elif not isinstance(value, UIElement): |
| 190 | raise CacheException( |
| 191 | "Failure while restoring cached values. " |
| 192 | "Unexpected stateful reference type " |
| 193 | f"({type(ref)}:{ref})." |
| 194 | ) |
| 195 | |
| 196 | def _restore_deps(self, value: Any) -> set[Name]: |
| 197 | """Cross-def names *value* needs before it can be restored. |
| 198 | |
| 199 | - A re-exec'd class/function needs the defs it references at |
| 200 | definition time (bases, decorators, class-body calls). |
| 201 | - A pickled instance of a cell-defined class needs that class |
| 202 | materialized first (tagged via `requires`). |
| 203 | """ |
| 204 | if isinstance(value, (ClassStub, FunctionStub)): |
| 205 | return _source_refs(value.code) |
| 206 | requires = getattr(value, "requires", "") |
no outgoing calls
searching dependent graphs…