base.py 99 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404
  1. """Collection of base classes."""
  2. from __future__ import annotations
  3. import contextlib
  4. import dataclasses
  5. import datetime
  6. import dis
  7. import functools
  8. import inspect
  9. import json
  10. import random
  11. import re
  12. import string
  13. import sys
  14. import warnings
  15. from types import CodeType, FunctionType
  16. from typing import (
  17. TYPE_CHECKING,
  18. Any,
  19. Callable,
  20. ClassVar,
  21. Dict,
  22. FrozenSet,
  23. Generic,
  24. Iterable,
  25. List,
  26. Literal,
  27. Mapping,
  28. NoReturn,
  29. Optional,
  30. Sequence,
  31. Set,
  32. Tuple,
  33. Type,
  34. TypeVar,
  35. Union,
  36. cast,
  37. get_args,
  38. overload,
  39. )
  40. from typing_extensions import (
  41. ParamSpec,
  42. Protocol,
  43. TypeGuard,
  44. deprecated,
  45. get_type_hints,
  46. override,
  47. )
  48. from reflex import constants
  49. from reflex.base import Base
  50. from reflex.constants.compiler import Hooks
  51. from reflex.utils import console, exceptions, imports, serializers, types
  52. from reflex.utils.exceptions import (
  53. UntypedComputedVarError,
  54. VarAttributeError,
  55. VarDependencyError,
  56. VarTypeError,
  57. VarValueError,
  58. )
  59. from reflex.utils.format import format_state_name
  60. from reflex.utils.imports import (
  61. ImmutableParsedImportDict,
  62. ImportDict,
  63. ImportVar,
  64. ParsedImportDict,
  65. parse_imports,
  66. )
  67. from reflex.utils.types import (
  68. GenericType,
  69. Self,
  70. _isinstance,
  71. get_origin,
  72. has_args,
  73. safe_issubclass,
  74. typehint_issubclass,
  75. unionize,
  76. )
  77. if TYPE_CHECKING:
  78. from reflex.components.component import BaseComponent
  79. from reflex.state import BaseState
  80. from .function import ArgsFunctionOperation
  81. from .number import BooleanVar, NumberVar
  82. from .object import ObjectVar
  83. from .sequence import ArrayVar, StringVar
  84. VAR_TYPE = TypeVar("VAR_TYPE", covariant=True)
  85. VALUE = TypeVar("VALUE")
  86. INT_OR_FLOAT = TypeVar("INT_OR_FLOAT", int, float)
  87. FAKE_VAR_TYPE = TypeVar("FAKE_VAR_TYPE")
  88. OTHER_VAR_TYPE = TypeVar("OTHER_VAR_TYPE")
  89. warnings.filterwarnings("ignore", message="fields may not start with an underscore")
  90. P = ParamSpec("P")
  91. R = TypeVar("R")
  92. class ReflexCallable(Protocol[P, R]):
  93. """Protocol for a callable."""
  94. __call__: Callable[P, R]
  95. if sys.version_info >= (3, 10):
  96. from types import EllipsisType
  97. ReflexCallableParams = Union[EllipsisType, Tuple[GenericType, ...]]
  98. else:
  99. ReflexCallableParams = Union[Any, Tuple[GenericType, ...]]
  100. def unwrap_reflex_callalbe(
  101. callable_type: GenericType,
  102. ) -> Tuple[ReflexCallableParams, GenericType]:
  103. """Unwrap the ReflexCallable type.
  104. Args:
  105. callable_type: The ReflexCallable type to unwrap.
  106. Returns:
  107. The unwrapped ReflexCallable type.
  108. """
  109. if callable_type is ReflexCallable:
  110. return Ellipsis, Any
  111. origin = get_origin(callable_type)
  112. if origin is not ReflexCallable:
  113. if origin in types.UnionTypes:
  114. args = get_args(callable_type)
  115. params: List[ReflexCallableParams] = []
  116. return_types: List[GenericType] = []
  117. for arg in args:
  118. param, return_type = unwrap_reflex_callalbe(arg)
  119. if param not in params:
  120. params.append(param)
  121. return_types.append(return_type)
  122. return (
  123. Ellipsis if len(params) > 1 else params[0],
  124. unionize(*return_types),
  125. )
  126. return Ellipsis, Any
  127. args = get_args(callable_type)
  128. if not args or len(args) != 2:
  129. return Ellipsis, Any
  130. return args
  131. _VAR_CACHING = True
  132. def get_var_caching() -> bool:
  133. """Get the var caching status.
  134. Returns:
  135. The var caching status.
  136. """
  137. return _VAR_CACHING
  138. def set_var_caching(value: bool):
  139. """Set the var caching status.
  140. Args:
  141. value: The value to set the var caching status to.
  142. """
  143. global _VAR_CACHING
  144. _VAR_CACHING = value
  145. @dataclasses.dataclass(
  146. eq=False,
  147. frozen=True,
  148. )
  149. class VarSubclassEntry:
  150. """Entry for a Var subclass."""
  151. var_subclass: Type[Var]
  152. to_var_subclass: Type[ToOperation]
  153. python_types: Tuple[GenericType, ...]
  154. is_subclass: Callable[[GenericType], bool] | None
  155. _var_subclasses: List[VarSubclassEntry] = []
  156. _var_literal_subclasses: List[Tuple[Type[LiteralVar], VarSubclassEntry]] = []
  157. @dataclasses.dataclass(
  158. eq=True,
  159. frozen=True,
  160. )
  161. class VarData:
  162. """Metadata associated with a x."""
  163. # The name of the enclosing state.
  164. state: str = dataclasses.field(default="")
  165. # The name of the field in the state.
  166. field_name: str = dataclasses.field(default="")
  167. # Imports needed to render this var
  168. imports: ImmutableParsedImportDict = dataclasses.field(default_factory=tuple)
  169. # Hooks that need to be present in the component to render this var
  170. hooks: Tuple[str, ...] = dataclasses.field(default_factory=tuple)
  171. # Components that need to be present in the component to render this var
  172. components: Tuple[BaseComponent, ...] = dataclasses.field(default_factory=tuple)
  173. # Dependencies of the var
  174. deps: Tuple[Var, ...] = dataclasses.field(default_factory=tuple)
  175. # Position of the hook in the component
  176. position: Hooks.HookPosition | None = None
  177. def __init__(
  178. self,
  179. state: str = "",
  180. field_name: str = "",
  181. imports: ImportDict | ParsedImportDict | None = None,
  182. hooks: Mapping[str, VarData | None] | None = None,
  183. components: Iterable[BaseComponent] | None = None,
  184. deps: list[Var] | None = None,
  185. position: Hooks.HookPosition | None = None,
  186. ):
  187. """Initialize the var data.
  188. Args:
  189. state: The name of the enclosing state.
  190. field_name: The name of the field in the state.
  191. imports: Imports needed to render this var.
  192. hooks: Hooks that need to be present in the component to render this var.
  193. components: Components that need to be present in the component to render this var.
  194. deps: Dependencies of the var for useCallback.
  195. position: Position of the hook in the component.
  196. """
  197. immutable_imports: ImmutableParsedImportDict = tuple(
  198. (k, tuple(v)) for k, v in parse_imports(imports or {}).items()
  199. )
  200. object.__setattr__(self, "state", state)
  201. object.__setattr__(self, "field_name", field_name)
  202. object.__setattr__(self, "imports", immutable_imports)
  203. object.__setattr__(self, "hooks", tuple(hooks or {}))
  204. object.__setattr__(
  205. self, "components", tuple(components) if components is not None else ()
  206. )
  207. object.__setattr__(self, "deps", tuple(deps or []))
  208. object.__setattr__(self, "position", position or None)
  209. def old_school_imports(self) -> ImportDict:
  210. """Return the imports as a mutable dict.
  211. Returns:
  212. The imports as a mutable dict.
  213. """
  214. return {k: list(v) for k, v in self.imports}
  215. def merge(*all: VarData | None) -> VarData | None:
  216. """Merge multiple var data objects.
  217. Returns:
  218. The merged var data object.
  219. Raises:
  220. ReflexError: If the positions of the var data objects are different.
  221. """
  222. all_var_datas = list(filter(None, all))
  223. if not all_var_datas:
  224. return None
  225. if len(all_var_datas) == 1:
  226. return all_var_datas[0]
  227. # Get the first non-empty field name or default to empty string.
  228. field_name = next(
  229. (var_data.field_name for var_data in all_var_datas if var_data.field_name),
  230. "",
  231. )
  232. # Get the first non-empty state or default to empty string.
  233. state = next(
  234. (var_data.state for var_data in all_var_datas if var_data.state), ""
  235. )
  236. hooks: dict[str, VarData | None] = {
  237. hook: None for var_data in all_var_datas for hook in var_data.hooks
  238. }
  239. _imports = imports.merge_imports(
  240. *(var_data.imports for var_data in all_var_datas)
  241. )
  242. deps = [dep for var_data in all_var_datas for dep in var_data.deps]
  243. positions = list(
  244. {
  245. var_data.position
  246. for var_data in all_var_datas
  247. if var_data.position is not None
  248. }
  249. )
  250. components = tuple(
  251. component for var_data in all_var_datas for component in var_data.components
  252. )
  253. if positions:
  254. if len(positions) > 1:
  255. raise exceptions.ReflexError(
  256. f"Cannot merge var data with different positions: {positions}"
  257. )
  258. position = positions[0]
  259. else:
  260. position = None
  261. return VarData(
  262. state=state,
  263. field_name=field_name,
  264. imports=_imports,
  265. hooks=hooks,
  266. deps=deps,
  267. position=position,
  268. components=components,
  269. )
  270. def __bool__(self) -> bool:
  271. """Check if the var data is non-empty.
  272. Returns:
  273. True if any field is set to a non-default value.
  274. """
  275. return any(getattr(self, field.name) for field in dataclasses.fields(self))
  276. @classmethod
  277. def from_state(cls, state: Type[BaseState] | str, field_name: str = "") -> VarData:
  278. """Set the state of the var.
  279. Args:
  280. state: The state to set or the full name of the state.
  281. field_name: The name of the field in the state. Optional.
  282. Returns:
  283. The var with the set state.
  284. """
  285. from reflex.utils import format
  286. state_name = state if isinstance(state, str) else state.get_full_name()
  287. return VarData(
  288. state=state_name,
  289. field_name=field_name,
  290. hooks={
  291. "const {0} = useContext(StateContexts.{0})".format(
  292. format.format_state_name(state_name)
  293. ): None
  294. },
  295. imports={
  296. f"$/{constants.Dirs.CONTEXTS_PATH}": [ImportVar(tag="StateContexts")],
  297. "react": [ImportVar(tag="useContext")],
  298. },
  299. )
  300. def _decode_var_immutable(value: str) -> tuple[VarData | None, str]:
  301. """Decode the state name from a formatted var.
  302. Args:
  303. value: The value to extract the state name from.
  304. Returns:
  305. The extracted state name and the value without the state name.
  306. """
  307. var_datas = []
  308. if isinstance(value, str):
  309. # fast path if there is no encoded VarData
  310. if constants.REFLEX_VAR_OPENING_TAG not in value:
  311. return None, value
  312. offset = 0
  313. # Find all tags.
  314. while m := _decode_var_pattern.search(value):
  315. start, end = m.span()
  316. value = value[:start] + value[end:]
  317. serialized_data = m.group(1)
  318. if serialized_data.isnumeric() or (
  319. serialized_data[0] == "-" and serialized_data[1:].isnumeric()
  320. ):
  321. # This is a global immutable var.
  322. var = _global_vars[int(serialized_data)]
  323. var_data = var._get_all_var_data()
  324. if var_data is not None:
  325. var_datas.append(var_data)
  326. offset += end - start
  327. return VarData.merge(*var_datas) if var_datas else None, value
  328. def can_use_in_object_var(cls: GenericType) -> bool:
  329. """Check if the class can be used in an ObjectVar.
  330. Args:
  331. cls: The class to check.
  332. Returns:
  333. Whether the class can be used in an ObjectVar.
  334. """
  335. if types.is_union(cls):
  336. return all(can_use_in_object_var(t) for t in types.get_args(cls))
  337. return (
  338. inspect.isclass(cls)
  339. and not issubclass(cls, Var)
  340. and serializers.can_serialize(cls, dict)
  341. )
  342. @dataclasses.dataclass(
  343. eq=False,
  344. frozen=True,
  345. )
  346. class Var(Generic[VAR_TYPE]):
  347. """Base class for immutable vars."""
  348. # The name of the var.
  349. _js_expr: str = dataclasses.field()
  350. # The type of the var.
  351. _var_type: types.GenericType = dataclasses.field(default=Any)
  352. # Extra metadata associated with the Var
  353. _var_data: Optional[VarData] = dataclasses.field(default=None)
  354. def __str__(self) -> str:
  355. """String representation of the var. Guaranteed to be a valid Javascript expression.
  356. Returns:
  357. The name of the var.
  358. """
  359. return self._js_expr
  360. @property
  361. def _var_is_local(self) -> bool:
  362. """Whether this is a local javascript variable.
  363. Returns:
  364. False
  365. """
  366. return False
  367. @property
  368. @deprecated("Use `_js_expr` instead.")
  369. def _var_name(self) -> str:
  370. """The name of the var.
  371. Returns:
  372. The name of the var.
  373. """
  374. return self._js_expr
  375. @property
  376. def _var_field_name(self) -> str:
  377. """The name of the field.
  378. Returns:
  379. The name of the field.
  380. """
  381. var_data = self._get_all_var_data()
  382. field_name = var_data.field_name if var_data else None
  383. return field_name or self._js_expr
  384. @property
  385. @deprecated("Use `_js_expr` instead.")
  386. def _var_name_unwrapped(self) -> str:
  387. """The name of the var without extra curly braces.
  388. Returns:
  389. The name of the var.
  390. """
  391. return self._js_expr
  392. @property
  393. def _var_is_string(self) -> bool:
  394. """Whether the var is a string literal.
  395. Returns:
  396. False
  397. """
  398. return False
  399. def __init_subclass__(
  400. cls,
  401. python_types: Tuple[GenericType, ...] | GenericType = types.Unset(),
  402. default_type: GenericType = types.Unset(),
  403. is_subclass: Callable[[GenericType], bool] | types.Unset = types.Unset(),
  404. **kwargs,
  405. ):
  406. """Initialize the subclass.
  407. Args:
  408. python_types: The python types that the var represents.
  409. default_type: The default type of the var. Defaults to the first python type.
  410. is_subclass: A function to check if a type is a subclass of the var.
  411. **kwargs: Additional keyword arguments.
  412. """
  413. super().__init_subclass__(**kwargs)
  414. if python_types or default_type or is_subclass:
  415. python_types = (
  416. (python_types if isinstance(python_types, tuple) else (python_types,))
  417. if python_types
  418. else ()
  419. )
  420. default_type = default_type or (python_types[0] if python_types else Any)
  421. @dataclasses.dataclass(
  422. eq=False,
  423. frozen=True,
  424. **{"slots": True} if sys.version_info >= (3, 10) else {},
  425. )
  426. class ToVarOperation(ToOperation, cls):
  427. """Base class of converting a var to another var type."""
  428. _original: Var = dataclasses.field(
  429. default=Var(_js_expr="null", _var_type=None),
  430. )
  431. _default_var_type: ClassVar[GenericType] = default_type
  432. ToVarOperation.__name__ = f'To{cls.__name__.removesuffix("Var")}Operation'
  433. _var_subclasses.append(
  434. VarSubclassEntry(
  435. cls,
  436. ToVarOperation,
  437. python_types,
  438. is_subclass if not isinstance(is_subclass, types.Unset) else None,
  439. )
  440. )
  441. def __post_init__(self):
  442. """Post-initialize the var."""
  443. # Decode any inline Var markup and apply it to the instance
  444. _var_data, _js_expr = _decode_var_immutable(self._js_expr)
  445. if _var_data or _js_expr != self._js_expr:
  446. self.__init__(
  447. **{
  448. **dataclasses.asdict(self),
  449. "_js_expr": _js_expr,
  450. "_var_data": VarData.merge(self._var_data, _var_data),
  451. }
  452. )
  453. def __hash__(self) -> int:
  454. """Define a hash function for the var.
  455. Returns:
  456. The hash of the var.
  457. """
  458. return hash((self._js_expr, self._var_type, self._var_data))
  459. def _get_all_var_data(self) -> VarData | None:
  460. """Get all VarData associated with the Var.
  461. Returns:
  462. The VarData of the components and all of its children.
  463. """
  464. return self._var_data
  465. def equals(self, other: Var) -> bool:
  466. """Check if two vars are equal.
  467. Args:
  468. other: The other var to compare.
  469. Returns:
  470. Whether the vars are equal.
  471. """
  472. return (
  473. self._js_expr == other._js_expr
  474. and self._var_type == other._var_type
  475. and self._get_all_var_data() == other._get_all_var_data()
  476. )
  477. @overload
  478. def _replace(
  479. self, _var_type: Type[OTHER_VAR_TYPE], merge_var_data=None, **kwargs: Any
  480. ) -> Var[OTHER_VAR_TYPE]: ...
  481. @overload
  482. def _replace(
  483. self, _var_type: GenericType | None = None, merge_var_data=None, **kwargs: Any
  484. ) -> Self: ...
  485. def _replace(
  486. self, _var_type: GenericType | None = None, merge_var_data=None, **kwargs: Any
  487. ) -> Self | Var:
  488. """Make a copy of this Var with updated fields.
  489. Args:
  490. merge_var_data: VarData to merge into the existing VarData.
  491. **kwargs: Var fields to update.
  492. Returns:
  493. A new Var with the updated fields overwriting the corresponding fields in this Var.
  494. Raises:
  495. TypeError: If _var_is_local, _var_is_string, or _var_full_name_needs_state_prefix is not None.
  496. """
  497. if kwargs.get("_var_is_local", False) is not False:
  498. raise TypeError("The _var_is_local argument is not supported for Var.")
  499. if kwargs.get("_var_is_string", False) is not False:
  500. raise TypeError("The _var_is_string argument is not supported for Var.")
  501. if kwargs.get("_var_full_name_needs_state_prefix", False) is not False:
  502. raise TypeError(
  503. "The _var_full_name_needs_state_prefix argument is not supported for Var."
  504. )
  505. value_with_replaced = dataclasses.replace(
  506. self,
  507. _var_type=_var_type or self._var_type,
  508. _var_data=VarData.merge(
  509. kwargs.get("_var_data", self._var_data), merge_var_data
  510. ),
  511. **kwargs,
  512. )
  513. if (js_expr := kwargs.get("_js_expr")) is not None:
  514. object.__setattr__(value_with_replaced, "_js_expr", js_expr)
  515. return value_with_replaced
  516. @classmethod
  517. def create(
  518. cls,
  519. value: FAKE_VAR_TYPE,
  520. _var_data: VarData | None = None,
  521. ) -> Var[FAKE_VAR_TYPE]:
  522. """Create a var from a value.
  523. Args:
  524. value: The value to create the var from.
  525. _var_data: Additional hooks and imports associated with the Var.
  526. Returns:
  527. The var.
  528. """
  529. # If the value is already a var, do nothing.
  530. if isinstance(value, Var):
  531. return value
  532. return LiteralVar.create(value, _var_data=_var_data)
  533. @classmethod
  534. @deprecated("Use `.create()` instead.")
  535. def create_safe(
  536. cls,
  537. *args: Any,
  538. **kwargs: Any,
  539. ) -> Var:
  540. """Create a var from a value.
  541. Args:
  542. *args: The arguments to create the var from.
  543. **kwargs: The keyword arguments to create the var from.
  544. Returns:
  545. The var.
  546. """
  547. return cls.create(*args, **kwargs)
  548. def __format__(self, format_spec: str) -> str:
  549. """Format the var into a Javascript equivalent to an f-string.
  550. Args:
  551. format_spec: The format specifier (Ignored for now).
  552. Returns:
  553. The formatted var.
  554. """
  555. hashed_var = hash(self)
  556. _global_vars[hashed_var] = self
  557. # Encode the _var_data into the formatted output for tracking purposes.
  558. return f"{constants.REFLEX_VAR_OPENING_TAG}{hashed_var}{constants.REFLEX_VAR_CLOSING_TAG}{self._js_expr}"
  559. @overload
  560. def to(self, output: Type[bool]) -> BooleanVar: ... # pyright: ignore [reportOverlappingOverload]
  561. @overload
  562. def to(self, output: Type[int]) -> NumberVar[int]: ...
  563. @overload
  564. def to(self, output: type[float]) -> NumberVar[float]: ...
  565. @overload
  566. def to(self, output: Type[str]) -> StringVar: ... # pyright: ignore [reportOverlappingOverload]
  567. @overload
  568. def to(
  569. self,
  570. output: type[Sequence[VALUE]] | type[set[VALUE]],
  571. ) -> ArrayVar[Sequence[VALUE]]: ...
  572. @overload
  573. def to(
  574. self,
  575. output: type[Mapping],
  576. ) -> ObjectVar[Mapping]: ...
  577. @overload
  578. def to(
  579. self, output: Type[ObjectVar], var_type: Type[VAR_INSIDE]
  580. ) -> ObjectVar[VAR_INSIDE]: ...
  581. @overload
  582. def to(
  583. self, output: Type[ObjectVar], var_type: None = None
  584. ) -> ObjectVar[VAR_TYPE]: ...
  585. @overload
  586. def to(self, output: VAR_SUBCLASS, var_type: None = None) -> VAR_SUBCLASS: ...
  587. @overload
  588. def to(
  589. self,
  590. output: Type[OUTPUT] | types.GenericType,
  591. var_type: types.GenericType | None = None,
  592. ) -> OUTPUT: ...
  593. def to(
  594. self,
  595. output: Type[OUTPUT] | types.GenericType,
  596. var_type: types.GenericType | None = None,
  597. ) -> Var:
  598. """Convert the var to a different type.
  599. Args:
  600. output: The output type.
  601. var_type: The type of the var.
  602. Returns:
  603. The converted var.
  604. """
  605. from .object import ObjectVar
  606. fixed_output_type = get_origin(output) or output
  607. # If the first argument is a python type, we map it to the corresponding Var type.
  608. for var_subclass in _var_subclasses[::-1]:
  609. if (
  610. var_subclass.python_types
  611. and safe_issubclass(fixed_output_type, var_subclass.python_types)
  612. ) or (
  613. var_subclass.is_subclass and var_subclass.is_subclass(fixed_output_type)
  614. ):
  615. return self.to(var_subclass.var_subclass, output)
  616. if fixed_output_type is None:
  617. return get_to_operation(NoneVar).create(self) # type: ignore
  618. # Handle fixed_output_type being Base or a dataclass.
  619. if can_use_in_object_var(fixed_output_type):
  620. return self.to(ObjectVar, output)
  621. if inspect.isclass(output):
  622. for var_subclass in _var_subclasses[::-1]:
  623. if issubclass(output, var_subclass.var_subclass):
  624. current_var_type = self._var_type
  625. if current_var_type is Any:
  626. new_var_type = var_type
  627. else:
  628. new_var_type = var_type or current_var_type
  629. to_operation_return = var_subclass.to_var_subclass.create(
  630. value=self, _var_type=new_var_type
  631. )
  632. return to_operation_return # type: ignore
  633. # If we can't determine the first argument, we just replace the _var_type.
  634. if not issubclass(output, Var) or var_type is None:
  635. return dataclasses.replace(
  636. self,
  637. _var_type=output,
  638. )
  639. # We couldn't determine the output type to be any other Var type, so we replace the _var_type.
  640. if var_type is not None:
  641. return dataclasses.replace(
  642. self,
  643. _var_type=var_type,
  644. )
  645. return self
  646. # We use `NoReturn` here to catch `Var[Any]` and `Var[Unknown]` cases first.
  647. @overload
  648. def guess_type(self: Var[NoReturn]) -> Var: ... # pyright: ignore [reportOverlappingOverload]
  649. @overload
  650. def guess_type(self: Var[bool]) -> BooleanVar: ...
  651. @overload
  652. def guess_type(self: Var[INT_OR_FLOAT]) -> NumberVar[INT_OR_FLOAT]: ...
  653. @overload
  654. def guess_type(self: Var[str]) -> StringVar: ... # pyright: ignore [reportOverlappingOverload]
  655. @overload
  656. def guess_type(self: Var[Sequence[VALUE]]) -> ArrayVar[Sequence[VALUE]]: ...
  657. @overload
  658. def guess_type(self: Var[Set[VALUE]]) -> ArrayVar[Set[VALUE]]: ...
  659. @overload
  660. def guess_type(
  661. self: Var[Dict[VALUE, OTHER_VAR_TYPE]],
  662. ) -> ObjectVar[Dict[VALUE, OTHER_VAR_TYPE]]: ...
  663. @overload
  664. def guess_type(self) -> Self: ...
  665. def guess_type(self) -> Var:
  666. """Guesses the type of the variable based on its `_var_type` attribute.
  667. Returns:
  668. Var: The guessed type of the variable.
  669. Raises:
  670. TypeError: If the type is not supported for guessing.
  671. """
  672. from .object import ObjectVar
  673. var_type = self._var_type
  674. if var_type is None:
  675. return self.to(None)
  676. if types.is_optional(var_type):
  677. var_type = types.get_args(var_type)[0]
  678. if var_type is Any:
  679. return self
  680. fixed_type = get_origin(var_type) or var_type
  681. if fixed_type in types.UnionTypes:
  682. inner_types = get_args(var_type)
  683. for var_subclass in _var_subclasses:
  684. if all(
  685. (
  686. safe_issubclass(t, var_subclass.python_types)
  687. or (var_subclass.is_subclass and var_subclass.is_subclass(t))
  688. )
  689. for t in inner_types
  690. ):
  691. return self.to(var_subclass.var_subclass, self._var_type)
  692. if can_use_in_object_var(var_type):
  693. return self.to(ObjectVar, self._var_type)
  694. return self
  695. if fixed_type is Literal:
  696. args = get_args(var_type)
  697. fixed_type = unionize(*(type(arg) for arg in args))
  698. if not inspect.isclass(fixed_type):
  699. raise TypeError(f"Unsupported type {var_type} for guess_type.")
  700. if fixed_type is None:
  701. return self.to(None)
  702. for var_subclass in _var_subclasses[::-1]:
  703. if safe_issubclass(fixed_type, var_subclass.python_types) or (
  704. var_subclass.is_subclass and var_subclass.is_subclass(fixed_type)
  705. ):
  706. return self.to(var_subclass.var_subclass, self._var_type)
  707. if can_use_in_object_var(fixed_type):
  708. return self.to(ObjectVar, self._var_type)
  709. return self
  710. def _get_default_value(self) -> Any:
  711. """Get the default value of the var.
  712. Returns:
  713. The default value of the var.
  714. Raises:
  715. ImportError: If the var is a dataframe and pandas is not installed.
  716. """
  717. if types.is_optional(self._var_type):
  718. return None
  719. type_ = (
  720. get_origin(self._var_type)
  721. if types.is_generic_alias(self._var_type)
  722. else self._var_type
  723. )
  724. if type_ is Literal:
  725. args = get_args(self._var_type)
  726. return args[0] if args else None
  727. if issubclass(type_, str):
  728. return ""
  729. if issubclass(type_, types.get_args(Union[int, float])):
  730. return 0
  731. if issubclass(type_, bool):
  732. return False
  733. if issubclass(type_, list):
  734. return []
  735. if issubclass(type_, Mapping):
  736. return {}
  737. if issubclass(type_, tuple):
  738. return ()
  739. if types.is_dataframe(type_):
  740. try:
  741. import pandas as pd
  742. return pd.DataFrame()
  743. except ImportError as e:
  744. raise ImportError(
  745. "Please install pandas to use dataframes in your app."
  746. ) from e
  747. return set() if issubclass(type_, set) else None
  748. def _get_setter_name(self, include_state: bool = True) -> str:
  749. """Get the name of the var's generated setter function.
  750. Args:
  751. include_state: Whether to include the state name in the setter name.
  752. Returns:
  753. The name of the setter function.
  754. """
  755. setter = constants.SETTER_PREFIX + self._var_field_name
  756. var_data = self._get_all_var_data()
  757. if var_data is None:
  758. return setter
  759. if not include_state or var_data.state == "":
  760. return setter
  761. return ".".join((var_data.state, setter))
  762. def _get_setter(self) -> Callable[[BaseState, Any], None]:
  763. """Get the var's setter function.
  764. Returns:
  765. A function that that creates a setter for the var.
  766. """
  767. actual_name = self._var_field_name
  768. def setter(state: BaseState, value: Any):
  769. """Get the setter for the var.
  770. Args:
  771. state: The state within which we add the setter function.
  772. value: The value to set.
  773. """
  774. if self._var_type in [int, float]:
  775. try:
  776. value = self._var_type(value)
  777. setattr(state, actual_name, value)
  778. except ValueError:
  779. console.debug(
  780. f"{type(state).__name__}.{self._js_expr}: Failed conversion of {value} to '{self._var_type.__name__}'. Value not set.",
  781. )
  782. else:
  783. setattr(state, actual_name, value)
  784. setter.__qualname__ = self._get_setter_name()
  785. return setter
  786. def _var_set_state(self, state: type[BaseState] | str):
  787. """Set the state of the var.
  788. Args:
  789. state: The state to set.
  790. Returns:
  791. The var with the state set.
  792. """
  793. formatted_state_name = (
  794. state
  795. if isinstance(state, str)
  796. else format_state_name(state.get_full_name())
  797. )
  798. return StateOperation.create(
  799. formatted_state_name,
  800. self,
  801. _var_data=VarData.merge(
  802. VarData.from_state(state, self._js_expr), self._var_data
  803. ),
  804. ).guess_type()
  805. def __eq__(self, other: Var | Any) -> BooleanVar:
  806. """Check if the current variable is equal to the given variable.
  807. Args:
  808. other (Var | Any): The variable to compare with.
  809. Returns:
  810. BooleanVar: A BooleanVar object representing the result of the equality check.
  811. """
  812. from .number import equal_operation
  813. return equal_operation(self, other).guess_type()
  814. def __ne__(self, other: Var | Any) -> BooleanVar:
  815. """Check if the current object is not equal to the given object.
  816. Parameters:
  817. other (Var | Any): The object to compare with.
  818. Returns:
  819. BooleanVar: A BooleanVar object representing the result of the comparison.
  820. """
  821. from .number import equal_operation
  822. return (~equal_operation(self, other)).guess_type()
  823. def bool(self) -> BooleanVar:
  824. """Convert the var to a boolean.
  825. Returns:
  826. The boolean var.
  827. """
  828. from .number import boolify
  829. return boolify(self) # pyright: ignore [reportReturnType]
  830. def __and__(self, other: Var | Any) -> Var:
  831. """Perform a logical AND operation on the current instance and another variable.
  832. Args:
  833. other: The variable to perform the logical AND operation with.
  834. Returns:
  835. A `BooleanVar` object representing the result of the logical AND operation.
  836. """
  837. return and_operation(self, other)
  838. def __rand__(self, other: Var | Any) -> Var:
  839. """Perform a logical AND operation on the current instance and another variable.
  840. Args:
  841. other: The variable to perform the logical AND operation with.
  842. Returns:
  843. A `BooleanVar` object representing the result of the logical AND operation.
  844. """
  845. return and_operation(other, self)
  846. def __or__(self, other: Var | Any) -> Var:
  847. """Perform a logical OR operation on the current instance and another variable.
  848. Args:
  849. other: The variable to perform the logical OR operation with.
  850. Returns:
  851. A `BooleanVar` object representing the result of the logical OR operation.
  852. """
  853. return or_operation(self, other)
  854. def __ror__(self, other: Var | Any) -> Var:
  855. """Perform a logical OR operation on the current instance and another variable.
  856. Args:
  857. other: The variable to perform the logical OR operation with.
  858. Returns:
  859. A `BooleanVar` object representing the result of the logical OR operation.
  860. """
  861. return or_operation(other, self)
  862. def __invert__(self) -> BooleanVar:
  863. """Perform a logical NOT operation on the current instance.
  864. Returns:
  865. A `BooleanVar` object representing the result of the logical NOT operation.
  866. """
  867. return (~self.bool()).guess_type()
  868. def to_string(self, use_json: bool = True) -> StringVar:
  869. """Convert the var to a string.
  870. Args:
  871. use_json: Whether to use JSON stringify. If False, uses Object.prototype.toString.
  872. Returns:
  873. The string var.
  874. """
  875. from .function import JSON_STRINGIFY, PROTOTYPE_TO_STRING
  876. from .sequence import StringVar
  877. return (
  878. JSON_STRINGIFY.call(self).to(StringVar)
  879. if use_json
  880. else PROTOTYPE_TO_STRING.call(self).to(StringVar)
  881. )
  882. def _as_ref(self) -> Var:
  883. """Get a reference to the var.
  884. Returns:
  885. The reference to the var.
  886. """
  887. from .object import ObjectVar
  888. refs = Var(
  889. _js_expr="refs",
  890. _var_data=VarData(
  891. imports={
  892. f"$/{constants.Dirs.STATE_PATH}": [imports.ImportVar(tag="refs")]
  893. }
  894. ),
  895. ).to(ObjectVar, Mapping[str, str])
  896. return refs[LiteralVar.create(str(self))]
  897. @deprecated("Use `.js_type()` instead.")
  898. def _type(self) -> StringVar:
  899. """Returns the type of the object.
  900. This method uses the `typeof` function from the `FunctionStringVar` class
  901. to determine the type of the object.
  902. Returns:
  903. StringVar: A string variable representing the type of the object.
  904. """
  905. return self.js_type()
  906. def js_type(self) -> StringVar:
  907. """Returns the javascript type of the object.
  908. This method uses the `typeof` function from the `FunctionStringVar` class
  909. to determine the type of the object.
  910. Returns:
  911. StringVar: A string variable representing the type of the object.
  912. """
  913. from .function import FunctionStringVar
  914. from .sequence import StringVar
  915. type_of = FunctionStringVar("typeof")
  916. return type_of.call(self).to(StringVar)
  917. def _without_data(self):
  918. """Create a copy of the var without the data.
  919. Returns:
  920. The var without the data.
  921. """
  922. return dataclasses.replace(self, _var_data=None)
  923. def __get__(self, instance: Any, owner: Any):
  924. """Get the var.
  925. Args:
  926. instance: The instance to get the var from.
  927. owner: The owner of the var.
  928. Returns:
  929. The var.
  930. """
  931. return self
  932. def __getattribute__(self, name: str) -> Any:
  933. """Get an attribute of the var.
  934. Args:
  935. name: The name of the attribute.
  936. Returns:
  937. The attribute.
  938. """
  939. if not _VAR_CACHING:
  940. try:
  941. self_dict = object.__getattribute__(self, "__dict__")
  942. for key in self_dict:
  943. if key.startswith("_cached_"):
  944. del self_dict[key]
  945. except Exception:
  946. pass
  947. return super().__getattribute__(name)
  948. def __getattr__(self, name: str):
  949. """Get an attribute of the var.
  950. Args:
  951. name: The name of the attribute.
  952. Returns:
  953. The attribute.
  954. Raises:
  955. VarAttributeError: If the attribute does not exist.
  956. TypeError: If the var type is Any.
  957. """
  958. if name.startswith("_"):
  959. return self.__getattribute__(name)
  960. if name == "contains":
  961. raise TypeError(
  962. f"Var of type {self._var_type} does not support contains check."
  963. )
  964. if name == "reverse":
  965. raise TypeError("Cannot reverse non-list var.")
  966. if self._var_type is Any:
  967. raise TypeError(
  968. f"You must provide an annotation for the state var `{self!s}`. Annotation cannot be `{self._var_type}`."
  969. )
  970. if name in REPLACED_NAMES:
  971. raise VarAttributeError(
  972. f"Field {name!r} was renamed to {REPLACED_NAMES[name]!r}"
  973. )
  974. raise VarAttributeError(
  975. f"The State var has no attribute '{name}' or may have been annotated wrongly.",
  976. )
  977. def _decode(self) -> Any:
  978. """Decode Var as a python value.
  979. Note that Var with state set cannot be decoded python-side and will be
  980. returned as full_name.
  981. Returns:
  982. The decoded value or the Var name.
  983. """
  984. if isinstance(self, LiteralVar):
  985. return self._var_value # type: ignore
  986. try:
  987. return json.loads(str(self))
  988. except ValueError:
  989. return str(self)
  990. @property
  991. def _var_state(self) -> str:
  992. """Compat method for getting the state.
  993. Returns:
  994. The state name associated with the var.
  995. """
  996. var_data = self._get_all_var_data()
  997. return var_data.state if var_data else ""
  998. @overload
  999. @classmethod
  1000. def range(cls, stop: int | NumberVar, /) -> ArrayVar[Sequence[int]]: ...
  1001. @overload
  1002. @classmethod
  1003. def range(
  1004. cls,
  1005. start: int | NumberVar,
  1006. end: int | NumberVar,
  1007. step: int | NumberVar = 1,
  1008. /,
  1009. ) -> ArrayVar[Sequence[int]]: ...
  1010. @classmethod
  1011. def range(
  1012. cls,
  1013. first_endpoint: int | Var[int],
  1014. second_endpoint: int | Var[int] | None = None,
  1015. step: int | Var[int] | None = None,
  1016. /,
  1017. ) -> ArrayVar[Sequence[int]]:
  1018. """Create a range of numbers.
  1019. Args:
  1020. first_endpoint: The end of the range if second_endpoint is not provided, otherwise the start of the range.
  1021. second_endpoint: The end of the range.
  1022. step: The step of the range.
  1023. Returns:
  1024. The range of numbers.
  1025. """
  1026. from .sequence import ArrayVar
  1027. if second_endpoint is None:
  1028. return ArrayVar.range.call(first_endpoint).guess_type()
  1029. if step is None:
  1030. return ArrayVar.range.call(first_endpoint, second_endpoint).guess_type()
  1031. return ArrayVar.range.call(first_endpoint, second_endpoint, step).guess_type()
  1032. def __bool__(self) -> bool:
  1033. """Raise exception if using Var in a boolean context.
  1034. Raises:
  1035. VarTypeError: when attempting to bool-ify the Var.
  1036. """
  1037. raise VarTypeError(
  1038. f"Cannot convert Var {str(self)!r} to bool for use with `if`, `and`, `or`, and `not`. "
  1039. "Instead use `rx.cond` and bitwise operators `&` (and), `|` (or), `~` (invert)."
  1040. )
  1041. def __iter__(self) -> Any:
  1042. """Raise exception if using Var in an iterable context.
  1043. Raises:
  1044. VarTypeError: when attempting to iterate over the Var.
  1045. """
  1046. raise VarTypeError(
  1047. f"Cannot iterate over Var {str(self)!r}. Instead use `rx.foreach`."
  1048. )
  1049. def __contains__(self, _: Any) -> Var:
  1050. """Override the 'in' operator to alert the user that it is not supported.
  1051. Raises:
  1052. VarTypeError: the operation is not supported
  1053. """
  1054. raise VarTypeError(
  1055. "'in' operator not supported for Var types, use Var.contains() instead."
  1056. )
  1057. OUTPUT = TypeVar("OUTPUT", bound=Var)
  1058. VAR_SUBCLASS = TypeVar("VAR_SUBCLASS", bound=Var)
  1059. VAR_INSIDE = TypeVar("VAR_INSIDE")
  1060. class VarWithDefault(Var[VAR_TYPE]):
  1061. """Annotate an optional argument."""
  1062. def __init__(self, default_value: VAR_TYPE):
  1063. """Initialize the default value.
  1064. Args:
  1065. default_value: The default value.
  1066. """
  1067. super().__init__("")
  1068. self._default = default_value
  1069. @property
  1070. def default(self) -> Var[VAR_TYPE]:
  1071. """Get the default value.
  1072. Returns:
  1073. The default value.
  1074. """
  1075. return Var.create(self._default)
  1076. class ToOperation:
  1077. """A var operation that converts a var to another type."""
  1078. def __getattr__(self, name: str) -> Any:
  1079. """Get an attribute of the var.
  1080. Args:
  1081. name: The name of the attribute.
  1082. Returns:
  1083. The attribute of the var.
  1084. """
  1085. from .object import ObjectVar
  1086. if isinstance(self, ObjectVar) and name != "_js_expr":
  1087. return ObjectVar.__getattr__(self, name)
  1088. return getattr(self._original, name)
  1089. def __post_init__(self):
  1090. """Post initialization."""
  1091. object.__delattr__(self, "_js_expr")
  1092. def __hash__(self) -> int:
  1093. """Calculate the hash value of the object.
  1094. Returns:
  1095. int: The hash value of the object.
  1096. """
  1097. return hash(self._original)
  1098. def _get_all_var_data(self) -> VarData | None:
  1099. """Get all the var data.
  1100. Returns:
  1101. The var data.
  1102. """
  1103. return VarData.merge(
  1104. self._original._get_all_var_data(),
  1105. self._var_data, # type: ignore
  1106. )
  1107. @classmethod
  1108. def create(
  1109. cls,
  1110. value: Var,
  1111. _var_type: GenericType | None = None,
  1112. _var_data: VarData | None = None,
  1113. ):
  1114. """Create a ToOperation.
  1115. Args:
  1116. value: The value of the var.
  1117. _var_type: The type of the Var.
  1118. _var_data: Additional hooks and imports associated with the Var.
  1119. Returns:
  1120. The ToOperation.
  1121. """
  1122. return cls(
  1123. _js_expr="", # type: ignore
  1124. _var_data=_var_data, # type: ignore
  1125. _var_type=_var_type or cls._default_var_type, # type: ignore
  1126. _original=value, # type: ignore
  1127. )
  1128. class LiteralVar(Var):
  1129. """Base class for immutable literal vars."""
  1130. def __init_subclass__(cls, **kwargs):
  1131. """Initialize the subclass.
  1132. Args:
  1133. **kwargs: Additional keyword arguments.
  1134. Raises:
  1135. TypeError: If the LiteralVar subclass does not have a corresponding Var subclass.
  1136. """
  1137. super().__init_subclass__(**kwargs)
  1138. bases = cls.__bases__
  1139. bases_normalized = [
  1140. base if inspect.isclass(base) else get_origin(base) for base in bases
  1141. ]
  1142. possible_bases = [
  1143. base
  1144. for base in bases_normalized
  1145. if issubclass(base, Var) and base != LiteralVar
  1146. ]
  1147. if not possible_bases:
  1148. raise TypeError(
  1149. f"LiteralVar subclass {cls} must have a base class that is a subclass of Var and not LiteralVar."
  1150. )
  1151. var_subclasses = [
  1152. var_subclass
  1153. for var_subclass in _var_subclasses
  1154. if var_subclass.var_subclass in possible_bases
  1155. ]
  1156. if not var_subclasses:
  1157. raise TypeError(
  1158. f"LiteralVar {cls} must have a base class annotated with `python_types`."
  1159. )
  1160. if len(var_subclasses) != 1:
  1161. raise TypeError(
  1162. f"LiteralVar {cls} must have exactly one base class annotated with `python_types`."
  1163. )
  1164. var_subclass = var_subclasses[0]
  1165. # Remove the old subclass, happens because __init_subclass__ is called twice
  1166. # for each subclass. This is because of __slots__ in dataclasses.
  1167. for var_literal_subclass in list(_var_literal_subclasses):
  1168. if var_literal_subclass[1] is var_subclass:
  1169. _var_literal_subclasses.remove(var_literal_subclass)
  1170. _var_literal_subclasses.append((cls, var_subclass))
  1171. @classmethod
  1172. def create(
  1173. cls,
  1174. value: Any,
  1175. _var_data: VarData | None = None,
  1176. ) -> Var:
  1177. """Create a var from a value.
  1178. Args:
  1179. value: The value to create the var from.
  1180. _var_data: Additional hooks and imports associated with the Var.
  1181. Returns:
  1182. The var.
  1183. Raises:
  1184. TypeError: If the value is not a supported type for LiteralVar.
  1185. """
  1186. if isinstance(value, Var):
  1187. if _var_data is None:
  1188. return value
  1189. return value._replace(merge_var_data=_var_data)
  1190. for literal_subclass, var_subclass in _var_literal_subclasses[::-1]:
  1191. if isinstance(value, var_subclass.python_types):
  1192. return literal_subclass.create(value, _var_data=_var_data)
  1193. from reflex.event import EventHandler
  1194. from reflex.utils.format import get_event_handler_parts
  1195. from .object import LiteralObjectVar
  1196. from .sequence import LiteralStringVar
  1197. if isinstance(value, EventHandler):
  1198. return Var(_js_expr=".".join(filter(None, get_event_handler_parts(value))))
  1199. serialized_value = serializers.serialize(value)
  1200. if serialized_value is not None:
  1201. if isinstance(serialized_value, Mapping):
  1202. return LiteralObjectVar.create(
  1203. serialized_value,
  1204. _var_type=type(value),
  1205. _var_data=_var_data,
  1206. )
  1207. if isinstance(serialized_value, str):
  1208. return LiteralStringVar.create(
  1209. serialized_value, _var_type=type(value), _var_data=_var_data
  1210. )
  1211. return LiteralVar.create(serialized_value, _var_data=_var_data)
  1212. if isinstance(value, Base):
  1213. # get the fields of the pydantic class
  1214. fields = value.__fields__.keys()
  1215. one_level_dict = {field: getattr(value, field) for field in fields}
  1216. return LiteralObjectVar.create(
  1217. {
  1218. field: value
  1219. for field, value in one_level_dict.items()
  1220. if not callable(value)
  1221. },
  1222. _var_type=type(value),
  1223. _var_data=_var_data,
  1224. )
  1225. if dataclasses.is_dataclass(value) and not isinstance(value, type):
  1226. return LiteralObjectVar.create(
  1227. {
  1228. k: (None if callable(v) else v)
  1229. for k, v in dataclasses.asdict(value).items()
  1230. },
  1231. _var_type=type(value),
  1232. _var_data=_var_data,
  1233. )
  1234. raise TypeError(
  1235. f"Unsupported type {type(value)} for LiteralVar. Tried to create a LiteralVar from {value}."
  1236. )
  1237. def __post_init__(self):
  1238. """Post-initialize the var."""
  1239. def json(self) -> str:
  1240. """Serialize the var to a JSON string.
  1241. Raises:
  1242. NotImplementedError: If the method is not implemented.
  1243. """
  1244. raise NotImplementedError(
  1245. "LiteralVar subclasses must implement the json method."
  1246. )
  1247. @serializers.serializer
  1248. def serialize_literal(value: LiteralVar):
  1249. """Serialize a Literal type.
  1250. Args:
  1251. value: The Literal to serialize.
  1252. Returns:
  1253. The serialized Literal.
  1254. """
  1255. return value._var_value
  1256. def get_python_literal(value: Union[LiteralVar, Any]) -> Any | None:
  1257. """Get the Python literal value.
  1258. Args:
  1259. value: The value to get the Python literal value of.
  1260. Returns:
  1261. The Python literal value.
  1262. """
  1263. if isinstance(value, LiteralVar):
  1264. return value._var_value
  1265. if isinstance(value, Var):
  1266. return None
  1267. return value
  1268. def validate_arg(type_hint: GenericType) -> Callable[[Any], str | None]:
  1269. """Create a validator for an argument.
  1270. Args:
  1271. type_hint: The type hint of the argument.
  1272. Returns:
  1273. The validator.
  1274. """
  1275. def validate(value: Any):
  1276. if isinstance(value, LiteralVar):
  1277. if not _isinstance(value._var_value, type_hint):
  1278. return f"Expected {type_hint} but got {value._var_value} of type {type(value._var_value)}."
  1279. elif isinstance(value, Var):
  1280. if not typehint_issubclass(value._var_type, type_hint):
  1281. return f"Expected {type_hint} but got {value._var_type}."
  1282. else:
  1283. if not _isinstance(value, type_hint):
  1284. return f"Expected {type_hint} but got {value} of type {type(value)}."
  1285. return validate
  1286. P = ParamSpec("P")
  1287. T = TypeVar("T")
  1288. V1 = TypeVar("V1")
  1289. V2 = TypeVar("V2")
  1290. V3 = TypeVar("V3")
  1291. V4 = TypeVar("V4")
  1292. V5 = TypeVar("V5")
  1293. class TypeComputer(Protocol):
  1294. """A protocol for type computers."""
  1295. def __call__(self, *args: Var) -> Tuple[GenericType, Union[TypeComputer, None]]:
  1296. """Compute the type of the operation.
  1297. Args:
  1298. *args: The arguments to compute the type of.
  1299. """
  1300. ...
  1301. @overload
  1302. def var_operation(
  1303. func: Callable[[Var[V1], Var[V2], Var[V3]], CustomVarOperationReturn[T]],
  1304. ) -> ArgsFunctionOperation[ReflexCallable[[V1, V2, V3], T]]: ...
  1305. @overload
  1306. def var_operation(
  1307. func: Callable[[Var[V1], Var[V2], VarWithDefault[V3]], CustomVarOperationReturn[T]],
  1308. ) -> ArgsFunctionOperation[ReflexCallable[[V1, V2, VarWithDefault[V3]], T]]: ...
  1309. @overload
  1310. def var_operation(
  1311. func: Callable[
  1312. [
  1313. Var[V1],
  1314. VarWithDefault[V2],
  1315. VarWithDefault[V3],
  1316. ],
  1317. CustomVarOperationReturn[T],
  1318. ],
  1319. ) -> ArgsFunctionOperation[
  1320. ReflexCallable[
  1321. [
  1322. V1,
  1323. VarWithDefault[V2],
  1324. VarWithDefault[V3],
  1325. ],
  1326. T,
  1327. ]
  1328. ]: ...
  1329. @overload
  1330. def var_operation(
  1331. func: Callable[
  1332. [
  1333. VarWithDefault[V1],
  1334. VarWithDefault[V2],
  1335. VarWithDefault[V3],
  1336. ],
  1337. CustomVarOperationReturn[T],
  1338. ],
  1339. ) -> ArgsFunctionOperation[
  1340. ReflexCallable[
  1341. [
  1342. VarWithDefault[V1],
  1343. VarWithDefault[V1],
  1344. VarWithDefault[V1],
  1345. ],
  1346. T,
  1347. ]
  1348. ]: ...
  1349. @overload
  1350. def var_operation(
  1351. func: Callable[[Var[V1], Var[V2]], CustomVarOperationReturn[T]],
  1352. ) -> ArgsFunctionOperation[ReflexCallable[[V1, V2], T]]: ...
  1353. @overload
  1354. def var_operation(
  1355. func: Callable[
  1356. [
  1357. Var[V1],
  1358. VarWithDefault[V2],
  1359. ],
  1360. CustomVarOperationReturn[T],
  1361. ],
  1362. ) -> ArgsFunctionOperation[
  1363. ReflexCallable[
  1364. [
  1365. V1,
  1366. VarWithDefault[V2],
  1367. ],
  1368. T,
  1369. ]
  1370. ]: ...
  1371. @overload
  1372. def var_operation(
  1373. func: Callable[
  1374. [
  1375. VarWithDefault[V1],
  1376. VarWithDefault[V2],
  1377. ],
  1378. CustomVarOperationReturn[T],
  1379. ],
  1380. ) -> ArgsFunctionOperation[
  1381. ReflexCallable[
  1382. [
  1383. VarWithDefault[V1],
  1384. VarWithDefault[V2],
  1385. ],
  1386. T,
  1387. ]
  1388. ]: ...
  1389. @overload
  1390. def var_operation(
  1391. func: Callable[[Var[V1]], CustomVarOperationReturn[T]],
  1392. ) -> ArgsFunctionOperation[ReflexCallable[[V1], T]]: ...
  1393. @overload
  1394. def var_operation(
  1395. func: Callable[
  1396. [VarWithDefault[V1]],
  1397. CustomVarOperationReturn[T],
  1398. ],
  1399. ) -> ArgsFunctionOperation[
  1400. ReflexCallable[
  1401. [VarWithDefault[V1]],
  1402. T,
  1403. ]
  1404. ]: ...
  1405. @overload
  1406. def var_operation(
  1407. func: Callable[[], CustomVarOperationReturn[T]],
  1408. ) -> ArgsFunctionOperation[ReflexCallable[[], T]]: ...
  1409. def var_operation(
  1410. func: Callable[..., CustomVarOperationReturn[T]],
  1411. ) -> ArgsFunctionOperation[ReflexCallable[..., T]]:
  1412. """Decorator for creating a var operation.
  1413. Example:
  1414. ```python
  1415. @var_operation
  1416. def add(a: Var[int], b: Var[int]):
  1417. return custom_var_operation(f"{a} + {b}")
  1418. ```
  1419. Args:
  1420. func: The function to decorate.
  1421. Returns:
  1422. The decorated function.
  1423. Raises:
  1424. TypeError: If the function has keyword-only arguments or arguments without Var type hints.
  1425. """
  1426. from .function import ArgsFunctionOperation, ReflexCallable
  1427. func_name = func.__name__
  1428. func_arg_spec = inspect.getfullargspec(func)
  1429. func_signature = inspect.signature(func)
  1430. if func_arg_spec.kwonlyargs:
  1431. raise TypeError(f"Function {func_name} cannot have keyword-only arguments.")
  1432. if func_arg_spec.varargs:
  1433. raise TypeError(f"Function {func_name} cannot have variable arguments.")
  1434. arg_names = func_arg_spec.args
  1435. arg_default_values: Sequence[inspect.Parameter.empty | VarWithDefault] = tuple(
  1436. (
  1437. default_value
  1438. if isinstance(
  1439. (default_value := func_signature.parameters[arg_name].default),
  1440. VarWithDefault,
  1441. )
  1442. else inspect.Parameter.empty()
  1443. )
  1444. for arg_name in arg_names
  1445. )
  1446. type_hints = get_type_hints(func)
  1447. if not all(
  1448. (get_origin((type_hint := type_hints.get(arg_name, Any))) or type_hint)
  1449. in (Var, VarWithDefault)
  1450. and len(get_args(type_hint)) <= 1
  1451. for arg_name in arg_names
  1452. ):
  1453. raise TypeError(
  1454. f"Function {func_name} must have type hints of the form `Var[Type]`."
  1455. )
  1456. args_with_type_hints = tuple(
  1457. (arg_name, (args[0] if (args := get_args(type_hints[arg_name])) else Any))
  1458. for arg_name in arg_names
  1459. )
  1460. arg_vars = tuple(
  1461. (
  1462. Var("_" + arg_name, _var_type=arg_python_type)
  1463. if not isinstance(arg_python_type, TypeVar)
  1464. else Var("_" + arg_name)
  1465. )
  1466. for arg_name, arg_python_type in args_with_type_hints
  1467. )
  1468. custom_operation_return = func(*arg_vars)
  1469. args_operation = ArgsFunctionOperation.create(
  1470. tuple(map(str, arg_vars)),
  1471. custom_operation_return,
  1472. default_values=arg_default_values,
  1473. validators=tuple(
  1474. validate_arg(arg_type)
  1475. if not isinstance(arg_type, TypeVar)
  1476. else validate_arg(arg_type.__bound__ or Any)
  1477. for _, arg_type in args_with_type_hints
  1478. ),
  1479. function_name=func_name,
  1480. type_computer=custom_operation_return._type_computer,
  1481. _raw_js_function=custom_operation_return._raw_js_function,
  1482. _var_type=ReflexCallable[
  1483. tuple(
  1484. arg_python_type
  1485. if isinstance(arg_default_values[i], inspect.Parameter)
  1486. else VarWithDefault[arg_python_type]
  1487. for i, (_, arg_python_type) in enumerate(args_with_type_hints)
  1488. ), # type: ignore
  1489. custom_operation_return._var_type,
  1490. ],
  1491. )
  1492. return args_operation
  1493. def figure_out_type(value: Any) -> types.GenericType:
  1494. """Figure out the type of the value.
  1495. Args:
  1496. value: The value to figure out the type of.
  1497. Returns:
  1498. The type of the value.
  1499. """
  1500. if isinstance(value, Var):
  1501. return value._var_type
  1502. type_ = type(value)
  1503. if has_args(type_):
  1504. return type_
  1505. if isinstance(value, list):
  1506. return List[unionize(*(figure_out_type(v) for v in value))]
  1507. if isinstance(value, set):
  1508. return Set[unionize(*(figure_out_type(v) for v in value))]
  1509. if isinstance(value, tuple):
  1510. return Tuple[unionize(*(figure_out_type(v) for v in value)), ...]
  1511. if isinstance(value, Mapping):
  1512. return Mapping[
  1513. unionize(*(figure_out_type(k) for k in value)),
  1514. unionize(*(figure_out_type(v) for v in value.values())),
  1515. ]
  1516. return type(value)
  1517. class cached_property_no_lock(functools.cached_property): # noqa: N801
  1518. """A special version of functools.cached_property that does not use a lock."""
  1519. def __init__(self, func):
  1520. """Initialize the cached_property_no_lock.
  1521. Args:
  1522. func: The function to cache.
  1523. """
  1524. super().__init__(func)
  1525. self.lock = contextlib.nullcontext()
  1526. class CachedVarOperation:
  1527. """Base class for cached var operations to lower boilerplate code."""
  1528. def __post_init__(self):
  1529. """Post-initialize the CachedVarOperation."""
  1530. object.__delattr__(self, "_js_expr")
  1531. def __getattr__(self, name: str) -> Any:
  1532. """Get an attribute of the var.
  1533. Args:
  1534. name: The name of the attribute.
  1535. Returns:
  1536. The attribute.
  1537. """
  1538. if name == "_js_expr":
  1539. return self._cached_var_name
  1540. parent_classes = inspect.getmro(type(self))
  1541. next_class = parent_classes[parent_classes.index(CachedVarOperation) + 1]
  1542. return next_class.__getattr__(self, name) # type: ignore
  1543. def _get_all_var_data(self) -> VarData | None:
  1544. """Get all VarData associated with the Var.
  1545. Returns:
  1546. The VarData of the components and all of its children.
  1547. """
  1548. return self._cached_get_all_var_data
  1549. @cached_property_no_lock
  1550. def _cached_get_all_var_data(self) -> VarData | None:
  1551. """Get the cached VarData.
  1552. Returns:
  1553. The cached VarData.
  1554. """
  1555. return VarData.merge(
  1556. *(
  1557. value._get_all_var_data() if isinstance(value, Var) else None
  1558. for value in (
  1559. getattr(self, field.name)
  1560. for field in dataclasses.fields(self) # type: ignore
  1561. )
  1562. ),
  1563. self._var_data,
  1564. )
  1565. def __hash__(self) -> int:
  1566. """Calculate the hash of the object.
  1567. Returns:
  1568. The hash of the object.
  1569. """
  1570. return hash(
  1571. (
  1572. type(self).__name__,
  1573. *[
  1574. getattr(self, field.name)
  1575. for field in dataclasses.fields(self) # type: ignore
  1576. if field.name not in ["_js_expr", "_var_data", "_var_type"]
  1577. ],
  1578. )
  1579. )
  1580. RETURN_TYPE = TypeVar("RETURN_TYPE")
  1581. DICT_KEY = TypeVar("DICT_KEY")
  1582. DICT_VAL = TypeVar("DICT_VAL")
  1583. LIST_INSIDE = TypeVar("LIST_INSIDE")
  1584. class FakeComputedVarBaseClass(property):
  1585. """A fake base class for ComputedVar to avoid inheriting from property."""
  1586. __pydantic_run_validation__ = False
  1587. def is_computed_var(obj: Any) -> TypeGuard[ComputedVar]:
  1588. """Check if the object is a ComputedVar.
  1589. Args:
  1590. obj: The object to check.
  1591. Returns:
  1592. Whether the object is a ComputedVar.
  1593. """
  1594. return isinstance(obj, FakeComputedVarBaseClass)
  1595. @dataclasses.dataclass(
  1596. eq=False,
  1597. frozen=True,
  1598. **{"slots": True} if sys.version_info >= (3, 10) else {},
  1599. )
  1600. class ComputedVar(Var[RETURN_TYPE]):
  1601. """A field with computed getters."""
  1602. # Whether to track dependencies and cache computed values
  1603. _cache: bool = dataclasses.field(default=False)
  1604. # Whether the computed var is a backend var
  1605. _backend: bool = dataclasses.field(default=False)
  1606. # The initial value of the computed var
  1607. _initial_value: RETURN_TYPE | types.Unset = dataclasses.field(default=types.Unset())
  1608. # Explicit var dependencies to track
  1609. _static_deps: set[str] = dataclasses.field(default_factory=set)
  1610. # Whether var dependencies should be auto-determined
  1611. _auto_deps: bool = dataclasses.field(default=True)
  1612. # Interval at which the computed var should be updated
  1613. _update_interval: Optional[datetime.timedelta] = dataclasses.field(default=None)
  1614. _fget: Callable[[BaseState], RETURN_TYPE] = dataclasses.field(
  1615. default_factory=lambda: lambda _: None
  1616. ) # type: ignore
  1617. def __init__(
  1618. self,
  1619. fget: Callable[[BASE_STATE], RETURN_TYPE],
  1620. initial_value: RETURN_TYPE | types.Unset = types.Unset(),
  1621. cache: bool = True,
  1622. deps: Optional[List[Union[str, Var]]] = None,
  1623. auto_deps: bool = True,
  1624. interval: Optional[Union[int, datetime.timedelta]] = None,
  1625. backend: bool | None = None,
  1626. **kwargs,
  1627. ):
  1628. """Initialize a ComputedVar.
  1629. Args:
  1630. fget: The getter function.
  1631. initial_value: The initial value of the computed var.
  1632. cache: Whether to cache the computed value.
  1633. deps: Explicit var dependencies to track.
  1634. auto_deps: Whether var dependencies should be auto-determined.
  1635. interval: Interval at which the computed var should be updated.
  1636. backend: Whether the computed var is a backend var.
  1637. **kwargs: additional attributes to set on the instance
  1638. Raises:
  1639. TypeError: If the computed var dependencies are not Var instances or var names.
  1640. UntypedComputedVarError: If the computed var is untyped.
  1641. """
  1642. hint = kwargs.pop("return_type", None) or get_type_hints(fget).get(
  1643. "return", Any
  1644. )
  1645. if hint is Any:
  1646. raise UntypedComputedVarError(var_name=fget.__name__)
  1647. kwargs.setdefault("_js_expr", fget.__name__)
  1648. kwargs.setdefault("_var_type", hint)
  1649. Var.__init__(
  1650. self,
  1651. _js_expr=kwargs.pop("_js_expr"),
  1652. _var_type=kwargs.pop("_var_type"),
  1653. _var_data=kwargs.pop("_var_data", None),
  1654. )
  1655. if kwargs:
  1656. raise TypeError(f"Unexpected keyword arguments: {tuple(kwargs)}")
  1657. if backend is None:
  1658. backend = fget.__name__.startswith("_")
  1659. object.__setattr__(self, "_backend", backend)
  1660. object.__setattr__(self, "_initial_value", initial_value)
  1661. object.__setattr__(self, "_cache", cache)
  1662. if isinstance(interval, int):
  1663. interval = datetime.timedelta(seconds=interval)
  1664. object.__setattr__(self, "_update_interval", interval)
  1665. if deps is None:
  1666. deps = []
  1667. else:
  1668. for dep in deps:
  1669. if isinstance(dep, Var):
  1670. continue
  1671. if isinstance(dep, str) and dep != "":
  1672. continue
  1673. raise TypeError(
  1674. "ComputedVar dependencies must be Var instances or var names (non-empty strings)."
  1675. )
  1676. object.__setattr__(
  1677. self,
  1678. "_static_deps",
  1679. {dep._js_expr if isinstance(dep, Var) else dep for dep in deps},
  1680. )
  1681. object.__setattr__(self, "_auto_deps", auto_deps)
  1682. object.__setattr__(self, "_fget", fget)
  1683. @override
  1684. def _replace(self, merge_var_data=None, **kwargs: Any) -> Self:
  1685. """Replace the attributes of the ComputedVar.
  1686. Args:
  1687. merge_var_data: VarData to merge into the existing VarData.
  1688. **kwargs: Var fields to update.
  1689. Returns:
  1690. The new ComputedVar instance.
  1691. Raises:
  1692. TypeError: If kwargs contains keys that are not allowed.
  1693. """
  1694. field_values = {
  1695. "fget": kwargs.pop("fget", self._fget),
  1696. "initial_value": kwargs.pop("initial_value", self._initial_value),
  1697. "cache": kwargs.pop("cache", self._cache),
  1698. "deps": kwargs.pop("deps", self._static_deps),
  1699. "auto_deps": kwargs.pop("auto_deps", self._auto_deps),
  1700. "interval": kwargs.pop("interval", self._update_interval),
  1701. "backend": kwargs.pop("backend", self._backend),
  1702. "_js_expr": kwargs.pop("_js_expr", self._js_expr),
  1703. "_var_type": kwargs.pop("_var_type", self._var_type),
  1704. "_var_data": kwargs.pop(
  1705. "_var_data", VarData.merge(self._var_data, merge_var_data)
  1706. ),
  1707. "return_type": kwargs.pop("return_type", self._var_type),
  1708. }
  1709. if kwargs:
  1710. unexpected_kwargs = ", ".join(kwargs.keys())
  1711. raise TypeError(f"Unexpected keyword arguments: {unexpected_kwargs}")
  1712. return type(self)(**field_values)
  1713. @property
  1714. def _cache_attr(self) -> str:
  1715. """Get the attribute used to cache the value on the instance.
  1716. Returns:
  1717. An attribute name.
  1718. """
  1719. return f"__cached_{self._js_expr}"
  1720. @property
  1721. def _last_updated_attr(self) -> str:
  1722. """Get the attribute used to store the last updated timestamp.
  1723. Returns:
  1724. An attribute name.
  1725. """
  1726. return f"__last_updated_{self._js_expr}"
  1727. def needs_update(self, instance: BaseState) -> bool:
  1728. """Check if the computed var needs to be updated.
  1729. Args:
  1730. instance: The state instance that the computed var is attached to.
  1731. Returns:
  1732. True if the computed var needs to be updated, False otherwise.
  1733. """
  1734. if self._update_interval is None:
  1735. return False
  1736. last_updated = getattr(instance, self._last_updated_attr, None)
  1737. if last_updated is None:
  1738. return True
  1739. return datetime.datetime.now() - last_updated > self._update_interval
  1740. @overload
  1741. def __get__(
  1742. self: ComputedVar[int] | ComputedVar[float],
  1743. instance: None,
  1744. owner: Type,
  1745. ) -> NumberVar: ...
  1746. @overload
  1747. def __get__(
  1748. self: ComputedVar[str],
  1749. instance: None,
  1750. owner: Type,
  1751. ) -> StringVar: ...
  1752. @overload
  1753. def __get__(
  1754. self: ComputedVar[Mapping[DICT_KEY, DICT_VAL]],
  1755. instance: None,
  1756. owner: Type,
  1757. ) -> ObjectVar[Mapping[DICT_KEY, DICT_VAL]]: ...
  1758. @overload
  1759. def __get__(
  1760. self: ComputedVar[Sequence[LIST_INSIDE]],
  1761. instance: None,
  1762. owner: Type,
  1763. ) -> ArrayVar[Sequence[LIST_INSIDE]]: ...
  1764. @overload
  1765. def __get__(
  1766. self: ComputedVar[set[LIST_INSIDE]],
  1767. instance: None,
  1768. owner: Type,
  1769. ) -> ArrayVar[set[LIST_INSIDE]]: ...
  1770. @overload
  1771. def __get__(self, instance: None, owner: Type) -> ComputedVar[RETURN_TYPE]: ...
  1772. @overload
  1773. def __get__(self, instance: BaseState, owner: Type) -> RETURN_TYPE: ...
  1774. def __get__(self, instance: BaseState | None, owner):
  1775. """Get the ComputedVar value.
  1776. If the value is already cached on the instance, return the cached value.
  1777. Args:
  1778. instance: the instance of the class accessing this computed var.
  1779. owner: the class that this descriptor is attached to.
  1780. Returns:
  1781. The value of the var for the given instance.
  1782. """
  1783. if instance is None:
  1784. state_where_defined = owner
  1785. while self._js_expr in state_where_defined.inherited_vars:
  1786. state_where_defined = state_where_defined.get_parent_state()
  1787. field_name = (
  1788. format_state_name(state_where_defined.get_full_name())
  1789. + "."
  1790. + self._js_expr
  1791. )
  1792. return dispatch(
  1793. field_name,
  1794. var_data=VarData.from_state(state_where_defined, self._js_expr),
  1795. result_var_type=self._var_type,
  1796. existing_var=self,
  1797. )
  1798. if not self._cache:
  1799. value = self.fget(instance)
  1800. else:
  1801. # handle caching
  1802. if not hasattr(instance, self._cache_attr) or self.needs_update(instance):
  1803. # Set cache attr on state instance.
  1804. setattr(instance, self._cache_attr, self.fget(instance))
  1805. # Ensure the computed var gets serialized to redis.
  1806. instance._was_touched = True
  1807. # Set the last updated timestamp on the state instance.
  1808. setattr(instance, self._last_updated_attr, datetime.datetime.now())
  1809. value = getattr(instance, self._cache_attr)
  1810. if not _isinstance(value, self._var_type):
  1811. console.error(
  1812. f"Computed var '{type(instance).__name__}.{self._js_expr}' must return"
  1813. f" type '{self._var_type}', got '{type(value)}'."
  1814. )
  1815. return value
  1816. def _deps(
  1817. self,
  1818. objclass: Type,
  1819. obj: FunctionType | CodeType | None = None,
  1820. self_name: Optional[str] = None,
  1821. ) -> set[str]:
  1822. """Determine var dependencies of this ComputedVar.
  1823. Save references to attributes accessed on "self". Recursively called
  1824. when the function makes a method call on "self" or define comprehensions
  1825. or nested functions that may reference "self".
  1826. Args:
  1827. objclass: the class obj this ComputedVar is attached to.
  1828. obj: the object to disassemble (defaults to the fget function).
  1829. self_name: if specified, look for this name in LOAD_FAST and LOAD_DEREF instructions.
  1830. Returns:
  1831. A set of variable names accessed by the given obj.
  1832. Raises:
  1833. VarValueError: if the function references the get_state, parent_state, or substates attributes
  1834. (cannot track deps in a related state, only implicitly via parent state).
  1835. """
  1836. if not self._auto_deps:
  1837. return self._static_deps
  1838. d = self._static_deps.copy()
  1839. if obj is None:
  1840. fget = self._fget
  1841. if fget is not None:
  1842. obj = cast(FunctionType, fget)
  1843. else:
  1844. return set()
  1845. with contextlib.suppress(AttributeError):
  1846. # unbox functools.partial
  1847. obj = cast(FunctionType, obj.func) # type: ignore
  1848. with contextlib.suppress(AttributeError):
  1849. # unbox EventHandler
  1850. obj = cast(FunctionType, obj.fn) # type: ignore
  1851. if self_name is None and isinstance(obj, FunctionType):
  1852. try:
  1853. # the first argument to the function is the name of "self" arg
  1854. self_name = obj.__code__.co_varnames[0]
  1855. except (AttributeError, IndexError):
  1856. self_name = None
  1857. if self_name is None:
  1858. # cannot reference attributes on self if method takes no args
  1859. return set()
  1860. invalid_names = ["get_state", "parent_state", "substates", "get_substate"]
  1861. self_is_top_of_stack = False
  1862. for instruction in dis.get_instructions(obj):
  1863. if (
  1864. instruction.opname in ("LOAD_FAST", "LOAD_DEREF")
  1865. and instruction.argval == self_name
  1866. ):
  1867. # bytecode loaded the class instance to the top of stack, next load instruction
  1868. # is referencing an attribute on self
  1869. self_is_top_of_stack = True
  1870. continue
  1871. if self_is_top_of_stack and instruction.opname in (
  1872. "LOAD_ATTR",
  1873. "LOAD_METHOD",
  1874. ):
  1875. try:
  1876. ref_obj = getattr(objclass, instruction.argval)
  1877. except Exception:
  1878. ref_obj = None
  1879. if instruction.argval in invalid_names:
  1880. raise VarValueError(
  1881. f"Cached var {self!s} cannot access arbitrary state via `{instruction.argval}`."
  1882. )
  1883. if callable(ref_obj):
  1884. # recurse into callable attributes
  1885. d.update(
  1886. self._deps(
  1887. objclass=objclass,
  1888. obj=ref_obj, # pyright: ignore [reportArgumentType]
  1889. )
  1890. )
  1891. # recurse into property fget functions
  1892. elif isinstance(ref_obj, property) and not isinstance(
  1893. ref_obj, ComputedVar
  1894. ):
  1895. d.update(
  1896. self._deps(
  1897. objclass=objclass,
  1898. obj=ref_obj.fget, # type: ignore
  1899. )
  1900. )
  1901. elif (
  1902. instruction.argval in objclass.backend_vars
  1903. or instruction.argval in objclass.vars
  1904. ):
  1905. # var access
  1906. d.add(instruction.argval)
  1907. elif instruction.opname == "LOAD_CONST" and isinstance(
  1908. instruction.argval, CodeType
  1909. ):
  1910. # recurse into nested functions / comprehensions, which can reference
  1911. # instance attributes from the outer scope
  1912. d.update(
  1913. self._deps(
  1914. objclass=objclass,
  1915. obj=instruction.argval,
  1916. self_name=self_name,
  1917. )
  1918. )
  1919. self_is_top_of_stack = False
  1920. return d
  1921. def mark_dirty(self, instance) -> None:
  1922. """Mark this ComputedVar as dirty.
  1923. Args:
  1924. instance: the state instance that needs to recompute the value.
  1925. """
  1926. with contextlib.suppress(AttributeError):
  1927. delattr(instance, self._cache_attr)
  1928. def _determine_var_type(self) -> GenericType:
  1929. """Get the type of the var.
  1930. Returns:
  1931. The type of the var.
  1932. """
  1933. hints = get_type_hints(self._fget)
  1934. if "return" in hints:
  1935. return hints["return"]
  1936. return Any
  1937. @property
  1938. def __class__(self) -> Type:
  1939. """Get the class of the var.
  1940. Returns:
  1941. The class of the var.
  1942. """
  1943. return FakeComputedVarBaseClass
  1944. @property
  1945. def fget(self) -> Callable[[BaseState], RETURN_TYPE]:
  1946. """Get the getter function.
  1947. Returns:
  1948. The getter function.
  1949. """
  1950. return self._fget
  1951. class DynamicRouteVar(ComputedVar[Union[str, List[str]]]):
  1952. """A ComputedVar that represents a dynamic route."""
  1953. pass
  1954. if TYPE_CHECKING:
  1955. BASE_STATE = TypeVar("BASE_STATE", bound=BaseState)
  1956. @overload
  1957. def computed_var(
  1958. fget: None = None,
  1959. initial_value: Any | types.Unset = types.Unset(),
  1960. cache: bool = True,
  1961. deps: Optional[List[Union[str, Var]]] = None,
  1962. auto_deps: bool = True,
  1963. interval: Optional[Union[datetime.timedelta, int]] = None,
  1964. backend: bool | None = None,
  1965. **kwargs,
  1966. ) -> Callable[[Callable[[BASE_STATE], RETURN_TYPE]], ComputedVar[RETURN_TYPE]]: ...
  1967. @overload
  1968. def computed_var(
  1969. fget: Callable[[BASE_STATE], RETURN_TYPE],
  1970. initial_value: RETURN_TYPE | types.Unset = types.Unset(),
  1971. cache: bool = True,
  1972. deps: Optional[List[Union[str, Var]]] = None,
  1973. auto_deps: bool = True,
  1974. interval: Optional[Union[datetime.timedelta, int]] = None,
  1975. backend: bool | None = None,
  1976. **kwargs,
  1977. ) -> ComputedVar[RETURN_TYPE]: ...
  1978. def computed_var(
  1979. fget: Callable[[BASE_STATE], Any] | None = None,
  1980. initial_value: Any | types.Unset = types.Unset(),
  1981. cache: bool = True,
  1982. deps: Optional[List[Union[str, Var]]] = None,
  1983. auto_deps: bool = True,
  1984. interval: Optional[Union[datetime.timedelta, int]] = None,
  1985. backend: bool | None = None,
  1986. **kwargs,
  1987. ) -> ComputedVar | Callable[[Callable[[BASE_STATE], Any]], ComputedVar]:
  1988. """A ComputedVar decorator with or without kwargs.
  1989. Args:
  1990. fget: The getter function.
  1991. initial_value: The initial value of the computed var.
  1992. cache: Whether to cache the computed value.
  1993. deps: Explicit var dependencies to track.
  1994. auto_deps: Whether var dependencies should be auto-determined.
  1995. interval: Interval at which the computed var should be updated.
  1996. backend: Whether the computed var is a backend var.
  1997. **kwargs: additional attributes to set on the instance
  1998. Returns:
  1999. A ComputedVar instance.
  2000. Raises:
  2001. ValueError: If caching is disabled and an update interval is set.
  2002. VarDependencyError: If user supplies dependencies without caching.
  2003. """
  2004. if cache is False and interval is not None:
  2005. raise ValueError("Cannot set update interval without caching.")
  2006. if cache is False and (deps is not None or auto_deps is False):
  2007. raise VarDependencyError("Cannot track dependencies without caching.")
  2008. if fget is not None:
  2009. return ComputedVar(fget, cache=cache)
  2010. def wrapper(fget: Callable[[BASE_STATE], Any]) -> ComputedVar:
  2011. return ComputedVar(
  2012. fget,
  2013. initial_value=initial_value,
  2014. cache=cache,
  2015. deps=deps,
  2016. auto_deps=auto_deps,
  2017. interval=interval,
  2018. backend=backend,
  2019. **kwargs,
  2020. )
  2021. return wrapper
  2022. RETURN = TypeVar("RETURN")
  2023. @dataclasses.dataclass(
  2024. eq=False,
  2025. frozen=True,
  2026. **{"slots": True} if sys.version_info >= (3, 10) else {},
  2027. )
  2028. class CustomVarOperationReturn(Var[RETURN]):
  2029. """Base class for custom var operations."""
  2030. _type_computer: TypeComputer | None = dataclasses.field(default=None)
  2031. _raw_js_function: str | None = dataclasses.field(default=None)
  2032. @classmethod
  2033. def create(
  2034. cls,
  2035. js_expression: str,
  2036. _var_type: Type[RETURN] | None = None,
  2037. _type_computer: TypeComputer | None = None,
  2038. _var_data: VarData | None = None,
  2039. _raw_js_function: str | None = None,
  2040. ) -> CustomVarOperationReturn[RETURN]:
  2041. """Create a CustomVarOperation.
  2042. Args:
  2043. js_expression: The JavaScript expression to evaluate.
  2044. _var_type: The type of the var.
  2045. _type_computer: A function to compute the type of the var given the arguments.
  2046. _var_data: Additional hooks and imports associated with the Var.
  2047. _raw_js_function: If provided, it will be used when the operation is being called with all of its arguments at once.
  2048. Returns:
  2049. The CustomVarOperation.
  2050. """
  2051. return CustomVarOperationReturn(
  2052. _js_expr=js_expression,
  2053. _var_type=_var_type or Any,
  2054. _type_computer=_type_computer,
  2055. _var_data=_var_data,
  2056. _raw_js_function=_raw_js_function,
  2057. )
  2058. def var_operation_return(
  2059. js_expression: str,
  2060. var_type: Type[RETURN] | None = None,
  2061. type_computer: Optional[TypeComputer] = None,
  2062. var_data: VarData | None = None,
  2063. _raw_js_function: str | None = None,
  2064. ) -> CustomVarOperationReturn[RETURN]:
  2065. """Shortcut for creating a CustomVarOperationReturn.
  2066. Args:
  2067. js_expression: The JavaScript expression to evaluate.
  2068. var_type: The type of the var.
  2069. type_computer: A function to compute the type of the var given the arguments.
  2070. var_data: Additional hooks and imports associated with the Var.
  2071. _raw_js_function: If provided, it will be used when the operation is being called with all of its arguments at once.
  2072. Returns:
  2073. The CustomVarOperationReturn.
  2074. """
  2075. return CustomVarOperationReturn.create(
  2076. js_expression=js_expression,
  2077. _var_type=var_type,
  2078. _type_computer=type_computer,
  2079. _var_data=var_data,
  2080. _raw_js_function=_raw_js_function,
  2081. )
  2082. @dataclasses.dataclass(
  2083. eq=False,
  2084. frozen=True,
  2085. **{"slots": True} if sys.version_info >= (3, 10) else {},
  2086. )
  2087. class CustomVarOperation(CachedVarOperation, Var[T]):
  2088. """Base class for custom var operations."""
  2089. _name: str = dataclasses.field(default="")
  2090. _args: Tuple[Tuple[str, Var], ...] = dataclasses.field(default_factory=tuple)
  2091. _return: CustomVarOperationReturn[T] = dataclasses.field(
  2092. default_factory=lambda: CustomVarOperationReturn.create("")
  2093. )
  2094. @cached_property_no_lock
  2095. def _cached_var_name(self) -> str:
  2096. """Get the cached var name.
  2097. Returns:
  2098. The cached var name.
  2099. """
  2100. return str(self._return)
  2101. @cached_property_no_lock
  2102. def _cached_get_all_var_data(self) -> VarData | None:
  2103. """Get the cached VarData.
  2104. Returns:
  2105. The cached VarData.
  2106. """
  2107. return VarData.merge(
  2108. *(arg[1]._get_all_var_data() for arg in self._args),
  2109. self._return._get_all_var_data(),
  2110. self._var_data,
  2111. )
  2112. @classmethod
  2113. def create(
  2114. cls,
  2115. name: str,
  2116. args: Tuple[Tuple[str, Var], ...],
  2117. return_var: CustomVarOperationReturn[T],
  2118. _var_data: VarData | None = None,
  2119. ) -> CustomVarOperation[T]:
  2120. """Create a CustomVarOperation.
  2121. Args:
  2122. name: The name of the operation.
  2123. args: The arguments to the operation.
  2124. return_var: The return var.
  2125. _var_data: Additional hooks and imports associated with the Var.
  2126. Returns:
  2127. The CustomVarOperation.
  2128. """
  2129. return CustomVarOperation(
  2130. _js_expr="",
  2131. _var_type=return_var._var_type,
  2132. _var_data=_var_data,
  2133. _name=name,
  2134. _args=args,
  2135. _return=return_var,
  2136. )
  2137. class NoneVar(Var[None], python_types=type(None)):
  2138. """A var representing None."""
  2139. @dataclasses.dataclass(
  2140. eq=False,
  2141. frozen=True,
  2142. **{"slots": True} if sys.version_info >= (3, 10) else {},
  2143. )
  2144. class LiteralNoneVar(LiteralVar, NoneVar):
  2145. """A var representing None."""
  2146. _var_value: None = None
  2147. def json(self) -> str:
  2148. """Serialize the var to a JSON string.
  2149. Returns:
  2150. The JSON string.
  2151. """
  2152. return "null"
  2153. @classmethod
  2154. def create(
  2155. cls,
  2156. value: None = None,
  2157. _var_data: VarData | None = None,
  2158. ) -> LiteralNoneVar:
  2159. """Create a var from a value.
  2160. Args:
  2161. value: The value of the var. Must be None. Existed for compatibility with LiteralVar.
  2162. _var_data: Additional hooks and imports associated with the Var.
  2163. Returns:
  2164. The var.
  2165. """
  2166. return LiteralNoneVar(
  2167. _js_expr="null",
  2168. _var_type=None,
  2169. _var_data=_var_data,
  2170. )
  2171. def get_to_operation(var_subclass: Type[Var]) -> Type[ToOperation]:
  2172. """Get the ToOperation class for a given Var subclass.
  2173. Args:
  2174. var_subclass: The Var subclass.
  2175. Returns:
  2176. The ToOperation class.
  2177. Raises:
  2178. ValueError: If the ToOperation class cannot be found.
  2179. """
  2180. possible_classes = [
  2181. saved_var_subclass.to_var_subclass
  2182. for saved_var_subclass in _var_subclasses
  2183. if saved_var_subclass.var_subclass is var_subclass
  2184. ]
  2185. if not possible_classes:
  2186. raise ValueError(f"Could not find ToOperation for {var_subclass}.")
  2187. return possible_classes[0]
  2188. @dataclasses.dataclass(
  2189. eq=False,
  2190. frozen=True,
  2191. **{"slots": True} if sys.version_info >= (3, 10) else {},
  2192. )
  2193. class StateOperation(CachedVarOperation, Var):
  2194. """A var operation that accesses a field on an object."""
  2195. _state_name: str = dataclasses.field(default="")
  2196. _field: Var = dataclasses.field(default_factory=lambda: LiteralNoneVar.create())
  2197. @cached_property_no_lock
  2198. def _cached_var_name(self) -> str:
  2199. """Get the cached var name.
  2200. Returns:
  2201. The cached var name.
  2202. """
  2203. return f"{self._state_name!s}.{self._field!s}"
  2204. def __getattr__(self, name: str) -> Any:
  2205. """Get an attribute of the var.
  2206. Args:
  2207. name: The name of the attribute.
  2208. Returns:
  2209. The attribute.
  2210. """
  2211. if name == "_js_expr":
  2212. return self._cached_var_name
  2213. return getattr(self._field, name)
  2214. @classmethod
  2215. def create(
  2216. cls,
  2217. state_name: str,
  2218. field: Var,
  2219. _var_data: VarData | None = None,
  2220. ) -> StateOperation:
  2221. """Create a DotOperation.
  2222. Args:
  2223. state_name: The name of the state.
  2224. field: The field of the state.
  2225. _var_data: Additional hooks and imports associated with the Var.
  2226. Returns:
  2227. The DotOperation.
  2228. """
  2229. return StateOperation(
  2230. _js_expr="",
  2231. _var_type=field._var_type,
  2232. _var_data=_var_data,
  2233. _state_name=state_name,
  2234. _field=field,
  2235. )
  2236. def get_uuid_string_var() -> Var:
  2237. """Return a Var that generates a single memoized UUID via .web/utils/state.js.
  2238. useMemo with an empty dependency array ensures that the generated UUID is
  2239. consistent across re-renders of the component.
  2240. Returns:
  2241. A Var that generates a UUID at runtime.
  2242. """
  2243. from reflex.utils.imports import ImportVar
  2244. from reflex.vars import Var
  2245. unique_uuid_var = get_unique_variable_name()
  2246. unique_uuid_var_data = VarData(
  2247. imports={
  2248. f"$/{constants.Dirs.STATE_PATH}": {ImportVar(tag="generateUUID")}, # type: ignore
  2249. "react": "useMemo",
  2250. },
  2251. hooks={f"const {unique_uuid_var} = useMemo(generateUUID, [])": None},
  2252. )
  2253. return Var(
  2254. _js_expr=unique_uuid_var,
  2255. _var_type=str,
  2256. _var_data=unique_uuid_var_data,
  2257. )
  2258. # Set of unique variable names.
  2259. USED_VARIABLES = set()
  2260. def get_unique_variable_name() -> str:
  2261. """Get a unique variable name.
  2262. Returns:
  2263. The unique variable name.
  2264. """
  2265. name = "".join([random.choice(string.ascii_lowercase) for _ in range(8)])
  2266. if name not in USED_VARIABLES:
  2267. USED_VARIABLES.add(name)
  2268. return name
  2269. return get_unique_variable_name()
  2270. # Compile regex for finding reflex var tags.
  2271. _decode_var_pattern_re = (
  2272. rf"{constants.REFLEX_VAR_OPENING_TAG}(.*?){constants.REFLEX_VAR_CLOSING_TAG}"
  2273. )
  2274. _decode_var_pattern = re.compile(_decode_var_pattern_re, flags=re.DOTALL)
  2275. # Defined global immutable vars.
  2276. _global_vars: Dict[int, Var] = {}
  2277. def _extract_var_data(value: Iterable) -> list[VarData | None]:
  2278. """Extract the var imports and hooks from an iterable containing a Var.
  2279. Args:
  2280. value: The iterable to extract the VarData from
  2281. Returns:
  2282. The extracted VarDatas.
  2283. """
  2284. from reflex.style import Style
  2285. from reflex.vars import Var
  2286. var_datas = []
  2287. with contextlib.suppress(TypeError):
  2288. for sub in value:
  2289. if isinstance(sub, Var):
  2290. var_datas.append(sub._var_data)
  2291. elif not isinstance(sub, str):
  2292. # Recurse into dict values.
  2293. if (
  2294. (values_fn := getattr(sub, "values", None)) is not None
  2295. and callable(values_fn)
  2296. and isinstance((values := values_fn()), Iterable)
  2297. ):
  2298. var_datas.extend(_extract_var_data(values))
  2299. # Recurse into iterable values (or dict keys).
  2300. var_datas.extend(_extract_var_data(sub))
  2301. # Style objects should already have _var_data.
  2302. if isinstance(value, Style):
  2303. var_datas.append(value._var_data)
  2304. else:
  2305. # Recurse when value is a dict itself.
  2306. values_fn = getattr(value, "values", None)
  2307. if callable(values_fn) and isinstance((values := values_fn()), Iterable):
  2308. var_datas.extend(_extract_var_data(values))
  2309. return var_datas
  2310. # These names were changed in reflex 0.3.0
  2311. REPLACED_NAMES = {
  2312. "full_name": "_var_full_name",
  2313. "name": "_js_expr",
  2314. "state": "_var_data.state",
  2315. "type_": "_var_type",
  2316. "is_local": "_var_is_local",
  2317. "is_string": "_var_is_string",
  2318. "set_state": "_var_set_state",
  2319. "deps": "_deps",
  2320. }
  2321. dispatchers: Dict[GenericType, Callable[[Var], Var]] = {}
  2322. def transform(fn: Callable[[Var], Var]) -> Callable[[Var], Var]:
  2323. """Register a function to transform a Var.
  2324. Args:
  2325. fn: The function to register.
  2326. Returns:
  2327. The decorator.
  2328. Raises:
  2329. TypeError: If the return type of the function is not a Var.
  2330. TypeError: If the Var return type does not have a generic type.
  2331. ValueError: If a function for the generic type is already registered.
  2332. """
  2333. return_type = fn.__annotations__["return"]
  2334. origin = get_origin(return_type)
  2335. if origin is not Var:
  2336. raise TypeError(
  2337. f"Expected return type of {fn.__name__} to be a Var, got {origin}."
  2338. )
  2339. generic_args = get_args(return_type)
  2340. if not generic_args:
  2341. raise TypeError(
  2342. f"Expected Var return type of {fn.__name__} to have a generic type."
  2343. )
  2344. generic_type = get_origin(generic_args[0]) or generic_args[0]
  2345. if generic_type in dispatchers:
  2346. raise ValueError(f"Function for {generic_type} already registered.")
  2347. dispatchers[generic_type] = fn
  2348. return fn
  2349. def generic_type_to_actual_type_map(
  2350. generic_type: GenericType, actual_type: GenericType
  2351. ) -> Dict[TypeVar, GenericType]:
  2352. """Map the generic type to the actual type.
  2353. Args:
  2354. generic_type: The generic type.
  2355. actual_type: The actual type.
  2356. Returns:
  2357. The mapping of type variables to actual types.
  2358. Raises:
  2359. TypeError: If the generic type and actual type do not match.
  2360. TypeError: If the number of generic arguments and actual arguments do not match.
  2361. """
  2362. generic_origin = get_origin(generic_type) or generic_type
  2363. actual_origin = get_origin(actual_type) or actual_type
  2364. if generic_origin is not actual_origin:
  2365. if isinstance(generic_origin, TypeVar):
  2366. return {generic_origin: actual_origin}
  2367. raise TypeError(
  2368. f"Type mismatch: expected {generic_origin}, got {actual_origin}."
  2369. )
  2370. generic_args = get_args(generic_type)
  2371. actual_args = get_args(actual_type)
  2372. if len(generic_args) != len(actual_args):
  2373. raise TypeError(
  2374. f"Number of generic arguments mismatch: expected {len(generic_args)}, got {len(actual_args)}."
  2375. )
  2376. # call recursively for nested generic types and merge the results
  2377. return {
  2378. k: v
  2379. for generic_arg, actual_arg in zip(generic_args, actual_args)
  2380. for k, v in generic_type_to_actual_type_map(generic_arg, actual_arg).items()
  2381. }
  2382. def resolve_generic_type_with_mapping(
  2383. generic_type: GenericType, type_mapping: Dict[TypeVar, GenericType]
  2384. ):
  2385. """Resolve a generic type with a type mapping.
  2386. Args:
  2387. generic_type: The generic type.
  2388. type_mapping: The type mapping.
  2389. Returns:
  2390. The resolved generic type.
  2391. """
  2392. if isinstance(generic_type, TypeVar):
  2393. return type_mapping.get(generic_type, generic_type)
  2394. generic_origin = get_origin(generic_type) or generic_type
  2395. generic_args = get_args(generic_type)
  2396. if not generic_args:
  2397. return generic_type
  2398. mapping_for_older_python = {
  2399. list: List,
  2400. set: Set,
  2401. dict: Dict,
  2402. tuple: Tuple,
  2403. frozenset: FrozenSet,
  2404. }
  2405. return mapping_for_older_python.get(generic_origin, generic_origin)[
  2406. tuple(
  2407. resolve_generic_type_with_mapping(arg, type_mapping) for arg in generic_args
  2408. )
  2409. ]
  2410. def resolve_arg_type_from_return_type(
  2411. arg_type: GenericType, return_type: GenericType, actual_return_type: GenericType
  2412. ) -> GenericType:
  2413. """Resolve the argument type from the return type.
  2414. Args:
  2415. arg_type: The argument type.
  2416. return_type: The return type.
  2417. actual_return_type: The requested return type.
  2418. Returns:
  2419. The argument type without the generics that are resolved.
  2420. """
  2421. return resolve_generic_type_with_mapping(
  2422. arg_type, generic_type_to_actual_type_map(return_type, actual_return_type)
  2423. )
  2424. def dispatch(
  2425. field_name: str,
  2426. var_data: VarData,
  2427. result_var_type: GenericType,
  2428. existing_var: Var | None = None,
  2429. ) -> Var:
  2430. """Dispatch a Var to the appropriate transformation function.
  2431. Args:
  2432. field_name: The name of the field.
  2433. var_data: The VarData associated with the Var.
  2434. result_var_type: The type of the Var.
  2435. existing_var: The existing Var to transform. Optional.
  2436. Returns:
  2437. The transformed Var.
  2438. Raises:
  2439. TypeError: If the return type of the function is not a Var.
  2440. TypeError: If the Var return type does not have a generic type.
  2441. TypeError: If the first argument of the function is not a Var.
  2442. TypeError: If the first argument of the function does not have a generic type
  2443. """
  2444. result_origin_var_type = get_origin(result_var_type) or result_var_type
  2445. if result_origin_var_type in dispatchers:
  2446. fn = dispatchers[result_origin_var_type]
  2447. fn_first_arg_type = next(
  2448. iter(inspect.signature(fn).parameters.values())
  2449. ).annotation
  2450. fn_return = inspect.signature(fn).return_annotation
  2451. fn_return_origin = get_origin(fn_return) or fn_return
  2452. if fn_return_origin is not Var:
  2453. raise TypeError(
  2454. f"Expected return type of {fn.__name__} to be a Var, got {fn_return}."
  2455. )
  2456. fn_return_generic_args = get_args(fn_return)
  2457. if not fn_return_generic_args:
  2458. raise TypeError(f"Expected generic type of {fn_return} to be a type.")
  2459. arg_origin = get_origin(fn_first_arg_type) or fn_first_arg_type
  2460. if arg_origin is not Var:
  2461. raise TypeError(
  2462. f"Expected first argument of {fn.__name__} to be a Var, got {fn_first_arg_type}."
  2463. )
  2464. arg_generic_args = get_args(fn_first_arg_type)
  2465. if not arg_generic_args:
  2466. raise TypeError(
  2467. f"Expected generic type of {fn_first_arg_type} to be a type."
  2468. )
  2469. arg_type = arg_generic_args[0]
  2470. fn_return_type = fn_return_generic_args[0]
  2471. var = (
  2472. Var(
  2473. field_name,
  2474. _var_data=var_data,
  2475. _var_type=resolve_arg_type_from_return_type(
  2476. arg_type, fn_return_type, result_var_type
  2477. ),
  2478. ).guess_type()
  2479. if existing_var is None
  2480. else existing_var._replace(
  2481. _var_type=resolve_arg_type_from_return_type(
  2482. arg_type, fn_return_type, result_var_type
  2483. ),
  2484. _var_data=var_data,
  2485. _js_expr=field_name,
  2486. ).guess_type()
  2487. )
  2488. return fn(var)
  2489. if existing_var is not None:
  2490. return existing_var._replace(
  2491. _js_expr=field_name,
  2492. _var_data=var_data,
  2493. _var_type=result_var_type,
  2494. ).guess_type()
  2495. return Var(
  2496. field_name,
  2497. _var_data=var_data,
  2498. _var_type=result_var_type,
  2499. ).guess_type()
  2500. V = TypeVar("V")
  2501. BASE_TYPE = TypeVar("BASE_TYPE", bound=Base)
  2502. FIELD_TYPE = TypeVar("FIELD_TYPE")
  2503. MAPPING_TYPE = TypeVar("MAPPING_TYPE", bound=Mapping)
  2504. class Field(Generic[FIELD_TYPE]):
  2505. """Shadow class for Var to allow for type hinting in the IDE."""
  2506. def __set__(self, instance, value: FIELD_TYPE):
  2507. """Set the Var.
  2508. Args:
  2509. instance: The instance of the class setting the Var.
  2510. value: The value to set the Var to.
  2511. """
  2512. @overload
  2513. def __get__(self: Field[bool], instance: None, owner) -> BooleanVar: ...
  2514. @overload
  2515. def __get__(self: Field[int], instance: None, owner) -> NumberVar[int]: ...
  2516. @overload
  2517. def __get__(self: Field[float], instance: None, owner) -> NumberVar[float]: ...
  2518. @overload
  2519. def __get__(self: Field[str], instance: None, owner) -> StringVar[str]: ...
  2520. @overload
  2521. def __get__(self: Field[None], instance: None, owner) -> NoneVar: ...
  2522. @overload
  2523. def __get__(
  2524. self: Field[Sequence[V]] | Field[Set[V]] | Field[List[V]],
  2525. instance: None,
  2526. owner,
  2527. ) -> ArrayVar[Sequence[V]]: ...
  2528. @overload
  2529. def __get__(
  2530. self: Field[MAPPING_TYPE], instance: None, owner
  2531. ) -> ObjectVar[MAPPING_TYPE]: ...
  2532. @overload
  2533. def __get__(
  2534. self: Field[BASE_TYPE], instance: None, owner
  2535. ) -> ObjectVar[BASE_TYPE]: ...
  2536. @overload
  2537. def __get__(self, instance: None, owner) -> Var[FIELD_TYPE]: ...
  2538. @overload
  2539. def __get__(self, instance, owner) -> FIELD_TYPE: ...
  2540. def __get__(self, instance, owner): # type: ignore
  2541. """Get the Var.
  2542. Args:
  2543. instance: The instance of the class accessing the Var.
  2544. owner: The class that the Var is attached to.
  2545. """
  2546. def field(value: FIELD_TYPE) -> Field[FIELD_TYPE]:
  2547. """Create a Field with a value.
  2548. Args:
  2549. value: The value of the Field.
  2550. Returns:
  2551. The Field.
  2552. """
  2553. return value # type: ignore
  2554. def and_operation(a: Var | Any, b: Var | Any) -> Var:
  2555. """Perform a logical AND operation on two variables.
  2556. Args:
  2557. a: The first variable.
  2558. b: The second variable.
  2559. Returns:
  2560. The result of the logical AND operation.
  2561. """
  2562. from .function import ArgsFunctionOperation
  2563. a = Var.create(a)
  2564. b = Var.create(b)
  2565. return _and_func_operation(
  2566. ArgsFunctionOperation.create((), a, _var_type=ReflexCallable[[], a._var_type]),
  2567. ArgsFunctionOperation.create((), b, _var_type=ReflexCallable[[], b._var_type]),
  2568. )
  2569. def or_operation(a: Var | Any, b: Var | Any) -> Var:
  2570. """Perform a logical OR operation on two variables.
  2571. Args:
  2572. a: The first variable.
  2573. b: The second variable.
  2574. Returns:
  2575. The result of the logical OR operation.
  2576. """
  2577. from .function import ArgsFunctionOperation
  2578. a = Var.create(a)
  2579. b = Var.create(b)
  2580. return _or_func_operation(
  2581. ArgsFunctionOperation.create((), a, _var_type=ReflexCallable[[], a._var_type]),
  2582. ArgsFunctionOperation.create((), b, _var_type=ReflexCallable[[], b._var_type]),
  2583. )
  2584. T_LOGICAL = TypeVar("T_LOGICAL")
  2585. U_LOGICAL = TypeVar("U_LOGICAL")
  2586. @var_operation
  2587. def _and_func_operation(
  2588. a: Var[ReflexCallable[[], T_LOGICAL]], b: Var[ReflexCallable[[], U_LOGICAL]]
  2589. ) -> CustomVarOperationReturn[ReflexCallable[[], Union[T_LOGICAL, U_LOGICAL]]]:
  2590. """Perform a logical AND operation on two variables.
  2591. Args:
  2592. a: The first variable.
  2593. b: The second variable.
  2594. Returns:
  2595. The result of the logical AND operation.
  2596. """
  2597. def type_computer(*args: Var):
  2598. if not args:
  2599. return (
  2600. ReflexCallable[[ReflexCallable[[], Any], ReflexCallable[[], Any]], Any],
  2601. type_computer,
  2602. )
  2603. if len(args) == 1:
  2604. return (
  2605. ReflexCallable[[ReflexCallable[[], Any]], Any],
  2606. functools.partial(type_computer, args[0]),
  2607. )
  2608. a_return_type = unwrap_reflex_callalbe(args[0]._var_type)[1]
  2609. b_return_type = unwrap_reflex_callalbe(args[1]._var_type)[1]
  2610. return (
  2611. ReflexCallable[[], unionize(a_return_type, b_return_type)],
  2612. None,
  2613. )
  2614. return var_operation_return(
  2615. js_expression=f"({a}() && {b}())",
  2616. type_computer=type_computer,
  2617. )
  2618. @var_operation
  2619. def _or_func_operation(
  2620. a: Var[ReflexCallable[[], T_LOGICAL]], b: Var[ReflexCallable[[], U_LOGICAL]]
  2621. ) -> CustomVarOperationReturn[ReflexCallable[[], Union[T_LOGICAL, U_LOGICAL]]]:
  2622. """Perform a logical OR operation on two variables.
  2623. Args:
  2624. a: The first variable.
  2625. b: The second variable.
  2626. Returns:
  2627. The result of the logical OR operation.
  2628. """
  2629. def type_computer(*args: Var):
  2630. if not args:
  2631. return (
  2632. ReflexCallable[[ReflexCallable[[], Any], ReflexCallable[[], Any]], Any],
  2633. type_computer,
  2634. )
  2635. if len(args) == 1:
  2636. return (
  2637. ReflexCallable[[ReflexCallable[[], Any]], Any],
  2638. functools.partial(type_computer, args[0]),
  2639. )
  2640. a_return_type = unwrap_reflex_callalbe(args[0]._var_type)[1]
  2641. b_return_type = unwrap_reflex_callalbe(args[1]._var_type)[1]
  2642. return (
  2643. ReflexCallable[[], unionize(a_return_type, b_return_type)],
  2644. None,
  2645. )
  2646. return var_operation_return(
  2647. js_expression=f"({a}() || {b}())",
  2648. type_computer=type_computer,
  2649. )
  2650. def passthrough_unary_type_computer(no_args: GenericType) -> TypeComputer:
  2651. """Create a type computer for unary operations.
  2652. Args:
  2653. no_args: The type to return when no arguments are provided.
  2654. Returns:
  2655. The type computer.
  2656. """
  2657. def type_computer(*args: Var):
  2658. if not args:
  2659. return (no_args, type_computer)
  2660. return (ReflexCallable[[], args[0]._var_type], None)
  2661. return type_computer
  2662. def unary_type_computer(
  2663. no_args: GenericType, computer: Callable[[Var], GenericType]
  2664. ) -> TypeComputer:
  2665. """Create a type computer for unary operations.
  2666. Args:
  2667. no_args: The type to return when no arguments are provided.
  2668. computer: The function to compute the type.
  2669. Returns:
  2670. The type computer.
  2671. """
  2672. def type_computer(*args: Var):
  2673. if not args:
  2674. return (no_args, type_computer)
  2675. return (ReflexCallable[[], computer(args[0])], None)
  2676. return type_computer
  2677. def nary_type_computer(
  2678. *types: GenericType, computer: Callable[..., GenericType]
  2679. ) -> TypeComputer:
  2680. """Create a type computer for n-ary operations.
  2681. Args:
  2682. types: The types to return when no arguments are provided.
  2683. computer: The function to compute the type.
  2684. Returns:
  2685. The type computer.
  2686. """
  2687. def type_computer(*args: Var):
  2688. if len(args) != len(types):
  2689. return (
  2690. types[len(args)],
  2691. functools.partial(type_computer, *args),
  2692. )
  2693. return (
  2694. ReflexCallable[[], computer(args)],
  2695. None,
  2696. )
  2697. return type_computer