|
1 | 1 | from __future__ import annotations |
2 | 2 |
|
| 3 | +from shiny.bookmark._serializers import Unserializable |
| 4 | + |
3 | 5 | __all__ = ("Session", "Inputs", "Outputs", "ClientData") |
4 | 6 |
|
5 | 7 | import asyncio |
@@ -1357,6 +1359,75 @@ def __contains__(self, key: str) -> bool: |
1357 | 1359 | def __dir__(self): |
1358 | 1360 | return list(self._map.keys()) |
1359 | 1361 |
|
| 1362 | + _serializers: dict[ |
| 1363 | + str, |
| 1364 | + Callable[ |
| 1365 | + [Any, Path | None], |
| 1366 | + Awaitable[Any | Unserializable], |
| 1367 | + ], |
| 1368 | + ] |
| 1369 | + |
| 1370 | + # This method can not be on the `Value` class as the _value_ may not exist when the |
| 1371 | + # "creating" method is executed. |
| 1372 | + # Ex: File inputs do not _make_ the input reactive value. The browser does when the |
| 1373 | + # client sets the value. |
| 1374 | + def set_serializer( |
| 1375 | + self, |
| 1376 | + id: str, |
| 1377 | + fn: ( |
| 1378 | + Callable[ |
| 1379 | + [Any, Path | None], |
| 1380 | + Awaitable[Any | Unserializable], |
| 1381 | + ] |
| 1382 | + | Callable[ |
| 1383 | + [Any, Path | None], |
| 1384 | + Any | Unserializable, |
| 1385 | + ] |
| 1386 | + ), |
| 1387 | + ) -> None: |
| 1388 | + """ |
| 1389 | + Add a function for serializing an input before bookmarking application state |
| 1390 | +
|
| 1391 | + Parameters |
| 1392 | + ---------- |
| 1393 | + id |
| 1394 | + The ID of the input value. |
| 1395 | + fn |
| 1396 | + A function that takes the input value and returns a modified value. The |
| 1397 | + returned value will be used for test snapshots and bookmarking. |
| 1398 | + """ |
| 1399 | + self._serializers[id] = wrap_async(fn) |
| 1400 | + |
| 1401 | + async def _serialize( |
| 1402 | + self, |
| 1403 | + /, |
| 1404 | + *, |
| 1405 | + exclude: list[str], |
| 1406 | + state_dir: Path | None, |
| 1407 | + ) -> dict[str, Any]: |
| 1408 | + from ..bookmark._serializers import serializer_default |
| 1409 | + |
| 1410 | + exclude_set = set(exclude) |
| 1411 | + serialized_values: dict[str, Any] = {} |
| 1412 | + |
| 1413 | + with reactive.isolate(): |
| 1414 | + |
| 1415 | + for key, value in self._map.items(): |
| 1416 | + if key in exclude_set: |
| 1417 | + continue |
| 1418 | + val = value() |
| 1419 | + |
| 1420 | + # Possibly apply custom serialization given the input id |
| 1421 | + serializer = self._serializers.get(key, serializer_default) |
| 1422 | + serialized_value = await serializer(val, state_dir) |
| 1423 | + |
| 1424 | + # Filter out any values that were marked as unserializable. |
| 1425 | + if isinstance(serialized_value, Unserializable): |
| 1426 | + continue |
| 1427 | + serialized_values[key] = serialized_value |
| 1428 | + |
| 1429 | + return serialized_values |
| 1430 | + |
1360 | 1431 |
|
1361 | 1432 | @add_example() |
1362 | 1433 | class ClientData: |
|
0 commit comments