foreach.py 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. """Create a list of components from an iterable."""
  2. from __future__ import annotations
  3. from typing import Any, Callable, List
  4. from pynecone.components.component import Component
  5. from pynecone.components.tags import IterTag
  6. from pynecone.var import BaseVar, Var, get_unique_variable_name
  7. class Foreach(Component):
  8. """A component that takes in an iterable and a render function and renders a list of components."""
  9. # The iterable to create components from.
  10. iterable: Var[List]
  11. # A function from the render args to the component.
  12. render_fn: Callable
  13. @classmethod
  14. def create(cls, iterable: Var[List], render_fn: Callable, **props) -> Foreach:
  15. """Create a foreach component.
  16. Args:
  17. iterable: The iterable to create components from.
  18. render_fn: A function from the render args to the component.
  19. **props: The attributes to pass to each child component.
  20. Returns:
  21. The foreach component.
  22. Raises:
  23. TypeError: If the iterable is of type Any.
  24. """
  25. try:
  26. type_ = iterable.type_.__args__[0]
  27. except Exception:
  28. type_ = Any
  29. iterable = Var.create(iterable) # type: ignore
  30. if iterable.type_ == Any:
  31. raise TypeError(
  32. f"Could not foreach over var of type Any. (If you are trying to foreach over a state var, add a type annotation to the var.)"
  33. )
  34. arg = BaseVar(name="_", type_=type_, is_local=True)
  35. return cls(
  36. iterable=iterable,
  37. render_fn=render_fn,
  38. children=[IterTag.render_component(render_fn, arg=arg)],
  39. **props,
  40. )
  41. def _render(self) -> IterTag:
  42. return IterTag(iterable=self.iterable, render_fn=self.render_fn)
  43. def render(self):
  44. """Render the component.
  45. Returns:
  46. The dictionary for template of component.
  47. """
  48. tag = self._render()
  49. try:
  50. type_ = self.iterable.type_.__args__[0]
  51. except Exception:
  52. type_ = Any
  53. arg = BaseVar(
  54. name=get_unique_variable_name(),
  55. type_=type_,
  56. )
  57. index_arg = tag.get_index_var_arg()
  58. component = tag.render_component(self.render_fn, arg)
  59. return dict(
  60. tag.add_props(
  61. **self.event_triggers,
  62. key=self.key,
  63. sx=self.style,
  64. id=self.id,
  65. class_name=self.class_name,
  66. ).set(
  67. children=[component.render()],
  68. props=tag.format_props(),
  69. ),
  70. iterable_state=tag.iterable.full_name,
  71. arg_name=arg.name,
  72. arg_index=index_arg,
  73. )