refreshable.py 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. from typing import Any, Callable, Dict, List, Tuple
  2. from typing_extensions import Self
  3. from .. import background_tasks, globals
  4. from ..dependencies import register_component
  5. from ..element import Element
  6. from ..helpers import is_coroutine
  7. register_component('refreshable', __file__, 'refreshable.js')
  8. class refreshable:
  9. def __init__(self, func: Callable[..., Any]) -> None:
  10. """Refreshable UI functions
  11. The `@ui.refreshable` decorator allows you to create functions that have a `refresh` method.
  12. This method will automatically delete all elements created by the function and recreate them.
  13. """
  14. self.func = func
  15. self.instance = None
  16. self.containers: List[Tuple[Element, List[Any], Dict[str, Any]]] = []
  17. def __get__(self, instance, _) -> Self:
  18. self.instance = instance
  19. return self
  20. def __call__(self, *args: Any, **kwargs: Any) -> None:
  21. self.prune()
  22. with Element('refreshable') as container:
  23. self.containers.append((container, args, kwargs))
  24. return self._run_in_container(container, *args, **kwargs)
  25. def refresh(self) -> None:
  26. self.prune()
  27. for container, args, kwargs in self.containers:
  28. container.clear()
  29. result = self._run_in_container(container, *args, **kwargs)
  30. if is_coroutine(self.func):
  31. if globals.loop and globals.loop.is_running():
  32. background_tasks.create(result)
  33. else:
  34. globals.app.on_startup(result)
  35. def prune(self) -> None:
  36. self.containers = [
  37. (container, args, kwargs)
  38. for container, args, kwargs in self.containers
  39. if container.client.id in globals.clients
  40. ]
  41. def _run_in_container(self, container: Element, *args: Any, **kwargs: Any) -> None:
  42. if is_coroutine(self.func):
  43. async def wait_for_result() -> None:
  44. with container:
  45. if self.instance is None:
  46. await self.func(*args, **kwargs)
  47. else:
  48. await self.func(self.instance, *args, **kwargs)
  49. return wait_for_result()
  50. else:
  51. with container:
  52. if self.instance is None:
  53. self.func(*args, **kwargs)
  54. else:
  55. self.func(self.instance, *args, **kwargs)