function.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. """Immutable function vars."""
  2. from __future__ import annotations
  3. import dataclasses
  4. import sys
  5. from typing import Any, Callable, Optional, Tuple, Type, Union
  6. from reflex.utils.types import GenericType
  7. from .base import CachedVarOperation, LiteralVar, Var, VarData, cached_property_no_lock
  8. class FunctionVar(Var[Callable], python_types=Callable):
  9. """Base class for immutable function vars."""
  10. def __call__(self, *args: Var | Any) -> ArgsFunctionOperation:
  11. """Call the function with the given arguments.
  12. Args:
  13. *args: The arguments to call the function with.
  14. Returns:
  15. The function call operation.
  16. """
  17. return ArgsFunctionOperation.create(
  18. ("...args",),
  19. VarOperationCall.create(self, *args, Var(_js_expr="...args")),
  20. )
  21. def call(self, *args: Var | Any) -> VarOperationCall:
  22. """Call the function with the given arguments.
  23. Args:
  24. *args: The arguments to call the function with.
  25. Returns:
  26. The function call operation.
  27. """
  28. return VarOperationCall.create(self, *args)
  29. class FunctionStringVar(FunctionVar):
  30. """Base class for immutable function vars from a string."""
  31. @classmethod
  32. def create(
  33. cls,
  34. func: str,
  35. _var_type: Type[Callable] = Callable,
  36. _var_data: VarData | None = None,
  37. ) -> FunctionStringVar:
  38. """Create a new function var from a string.
  39. Args:
  40. func: The function to call.
  41. _var_data: Additional hooks and imports associated with the Var.
  42. Returns:
  43. The function var.
  44. """
  45. return cls(
  46. _js_expr=func,
  47. _var_type=_var_type,
  48. _var_data=_var_data,
  49. )
  50. @dataclasses.dataclass(
  51. eq=False,
  52. frozen=True,
  53. **{"slots": True} if sys.version_info >= (3, 10) else {},
  54. )
  55. class VarOperationCall(CachedVarOperation, Var):
  56. """Base class for immutable vars that are the result of a function call."""
  57. _func: Optional[FunctionVar] = dataclasses.field(default=None)
  58. _args: Tuple[Union[Var, Any], ...] = dataclasses.field(default_factory=tuple)
  59. @cached_property_no_lock
  60. def _cached_var_name(self) -> str:
  61. """The name of the var.
  62. Returns:
  63. The name of the var.
  64. """
  65. return f"({str(self._func)}({', '.join([str(LiteralVar.create(arg)) for arg in self._args])}))"
  66. @cached_property_no_lock
  67. def _cached_get_all_var_data(self) -> VarData | None:
  68. """Get all the var data associated with the var.
  69. Returns:
  70. All the var data associated with the var.
  71. """
  72. return VarData.merge(
  73. self._func._get_all_var_data() if self._func is not None else None,
  74. *[LiteralVar.create(arg)._get_all_var_data() for arg in self._args],
  75. self._var_data,
  76. )
  77. @classmethod
  78. def create(
  79. cls,
  80. func: FunctionVar,
  81. *args: Var | Any,
  82. _var_type: GenericType = Any,
  83. _var_data: VarData | None = None,
  84. ) -> VarOperationCall:
  85. """Create a new function call var.
  86. Args:
  87. func: The function to call.
  88. *args: The arguments to call the function with.
  89. _var_data: Additional hooks and imports associated with the Var.
  90. Returns:
  91. The function call var.
  92. """
  93. return cls(
  94. _js_expr="",
  95. _var_type=_var_type,
  96. _var_data=_var_data,
  97. _func=func,
  98. _args=args,
  99. )
  100. @dataclasses.dataclass(
  101. eq=False,
  102. frozen=True,
  103. **{"slots": True} if sys.version_info >= (3, 10) else {},
  104. )
  105. class ArgsFunctionOperation(CachedVarOperation, FunctionVar):
  106. """Base class for immutable function defined via arguments and return expression."""
  107. _args_names: Tuple[str, ...] = dataclasses.field(default_factory=tuple)
  108. _return_expr: Union[Var, Any] = dataclasses.field(default=None)
  109. @cached_property_no_lock
  110. def _cached_var_name(self) -> str:
  111. """The name of the var.
  112. Returns:
  113. The name of the var.
  114. """
  115. return f"(({', '.join(self._args_names)}) => ({str(LiteralVar.create(self._return_expr))}))"
  116. @classmethod
  117. def create(
  118. cls,
  119. args_names: Tuple[str, ...],
  120. return_expr: Var | Any,
  121. _var_type: GenericType = Callable,
  122. _var_data: VarData | None = None,
  123. ) -> ArgsFunctionOperation:
  124. """Create a new function var.
  125. Args:
  126. args_names: The names of the arguments.
  127. return_expr: The return expression of the function.
  128. _var_data: Additional hooks and imports associated with the Var.
  129. Returns:
  130. The function var.
  131. """
  132. return cls(
  133. _js_expr="",
  134. _var_type=_var_type,
  135. _var_data=_var_data,
  136. _args_names=args_names,
  137. _return_expr=return_expr,
  138. )
  139. JSON_STRINGIFY = FunctionStringVar.create("JSON.stringify")
  140. ARRAY_ISARRAY = FunctionStringVar.create("Array.isArray")
  141. PROTOTYPE_TO_STRING = FunctionStringVar.create(
  142. "((__to_string) => __to_string.toString())"
  143. )