function.py 5.1 KB

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