1
0

test_var.py 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123
  1. import json
  2. import typing
  3. from typing import Dict, List, Set, Tuple
  4. import pytest
  5. from pandas import DataFrame
  6. from reflex.base import Base
  7. from reflex.state import State
  8. from reflex.vars import (
  9. BaseVar,
  10. ComputedVar,
  11. ImportVar,
  12. Var,
  13. )
  14. test_vars = [
  15. BaseVar(_var_name="prop1", _var_type=int),
  16. BaseVar(_var_name="key", _var_type=str),
  17. BaseVar(_var_name="value", _var_type=str, _var_state="state"),
  18. BaseVar(_var_name="local", _var_type=str, _var_state="state", _var_is_local=True),
  19. BaseVar(_var_name="local2", _var_type=str, _var_is_local=True),
  20. ]
  21. test_import_vars = [ImportVar(tag="DataGrid"), ImportVar(tag="DataGrid", alias="Grid")]
  22. class BaseState(State):
  23. """A Test State."""
  24. val: str = "key"
  25. @pytest.fixture
  26. def TestObj():
  27. class TestObj(Base):
  28. foo: int
  29. bar: str
  30. return TestObj
  31. @pytest.fixture
  32. def ParentState(TestObj):
  33. class ParentState(State):
  34. foo: int
  35. bar: int
  36. @ComputedVar
  37. def var_without_annotation(self):
  38. return TestObj
  39. return ParentState
  40. @pytest.fixture
  41. def ChildState(ParentState, TestObj):
  42. class ChildState(ParentState):
  43. @ComputedVar
  44. def var_without_annotation(self):
  45. return TestObj
  46. return ChildState
  47. @pytest.fixture
  48. def GrandChildState(ChildState, TestObj):
  49. class GrandChildState(ChildState):
  50. @ComputedVar
  51. def var_without_annotation(self):
  52. return TestObj
  53. return GrandChildState
  54. @pytest.fixture
  55. def StateWithAnyVar(TestObj):
  56. class StateWithAnyVar(State):
  57. @ComputedVar
  58. def var_without_annotation(self) -> typing.Any:
  59. return TestObj
  60. return StateWithAnyVar
  61. @pytest.fixture
  62. def StateWithCorrectVarAnnotation():
  63. class StateWithCorrectVarAnnotation(State):
  64. @ComputedVar
  65. def var_with_annotation(self) -> str:
  66. return "Correct annotation"
  67. return StateWithCorrectVarAnnotation
  68. @pytest.fixture
  69. def StateWithWrongVarAnnotation(TestObj):
  70. class StateWithWrongVarAnnotation(State):
  71. @ComputedVar
  72. def var_with_annotation(self) -> str:
  73. return TestObj
  74. return StateWithWrongVarAnnotation
  75. @pytest.mark.parametrize(
  76. "prop,expected",
  77. zip(
  78. test_vars,
  79. [
  80. "prop1",
  81. "key",
  82. "state.value",
  83. "state.local",
  84. "local2",
  85. ],
  86. ),
  87. )
  88. def test_full_name(prop, expected):
  89. """Test that the full name of a var is correct.
  90. Args:
  91. prop: The var to test.
  92. expected: The expected full name.
  93. """
  94. assert prop._var_full_name == expected
  95. @pytest.mark.parametrize(
  96. "prop,expected",
  97. zip(
  98. test_vars,
  99. ["{prop1}", "{key}", "{state.value}", "state.local", "local2"],
  100. ),
  101. )
  102. def test_str(prop, expected):
  103. """Test that the string representation of a var is correct.
  104. Args:
  105. prop: The var to test.
  106. expected: The expected string representation.
  107. """
  108. assert str(prop) == expected
  109. @pytest.mark.parametrize(
  110. "prop,expected",
  111. [
  112. (BaseVar(_var_name="p", _var_type=int), 0),
  113. (BaseVar(_var_name="p", _var_type=float), 0.0),
  114. (BaseVar(_var_name="p", _var_type=str), ""),
  115. (BaseVar(_var_name="p", _var_type=bool), False),
  116. (BaseVar(_var_name="p", _var_type=list), []),
  117. (BaseVar(_var_name="p", _var_type=dict), {}),
  118. (BaseVar(_var_name="p", _var_type=tuple), ()),
  119. (BaseVar(_var_name="p", _var_type=set), set()),
  120. ],
  121. )
  122. def test_default_value(prop, expected):
  123. """Test that the default value of a var is correct.
  124. Args:
  125. prop: The var to test.
  126. expected: The expected default value.
  127. """
  128. assert prop.get_default_value() == expected
  129. @pytest.mark.parametrize(
  130. "prop,expected",
  131. zip(
  132. test_vars,
  133. [
  134. "set_prop1",
  135. "set_key",
  136. "state.set_value",
  137. "state.set_local",
  138. "set_local2",
  139. ],
  140. ),
  141. )
  142. def test_get_setter(prop, expected):
  143. """Test that the name of the setter function of a var is correct.
  144. Args:
  145. prop: The var to test.
  146. expected: The expected name of the setter function.
  147. """
  148. assert prop.get_setter_name() == expected
  149. @pytest.mark.parametrize(
  150. "value,expected",
  151. [
  152. (None, None),
  153. (1, BaseVar(_var_name="1", _var_type=int, _var_is_local=True)),
  154. ("key", BaseVar(_var_name="key", _var_type=str, _var_is_local=True)),
  155. (3.14, BaseVar(_var_name="3.14", _var_type=float, _var_is_local=True)),
  156. ([1, 2, 3], BaseVar(_var_name="[1, 2, 3]", _var_type=list, _var_is_local=True)),
  157. (
  158. {"a": 1, "b": 2},
  159. BaseVar(_var_name='{"a": 1, "b": 2}', _var_type=dict, _var_is_local=True),
  160. ),
  161. ],
  162. )
  163. def test_create(value, expected):
  164. """Test the var create function.
  165. Args:
  166. value: The value to create a var from.
  167. expected: The expected name of the setter function.
  168. """
  169. prop = Var.create(value)
  170. if value is None:
  171. assert prop == expected
  172. else:
  173. assert prop.equals(expected) # type: ignore
  174. def test_create_type_error():
  175. """Test the var create function when inputs type error."""
  176. class ErrorType:
  177. pass
  178. value = ErrorType()
  179. with pytest.raises(TypeError):
  180. Var.create(value)
  181. def v(value) -> Var:
  182. val = (
  183. Var.create(json.dumps(value), _var_is_string=True, _var_is_local=False)
  184. if isinstance(value, str)
  185. else Var.create(value, _var_is_local=False)
  186. )
  187. assert val is not None
  188. return val
  189. def test_basic_operations(TestObj):
  190. """Test the var operations.
  191. Args:
  192. TestObj: The test object.
  193. """
  194. assert str(v(1) == v(2)) == "{(1 === 2)}"
  195. assert str(v(1) != v(2)) == "{(1 !== 2)}"
  196. assert str(v(1) < v(2)) == "{(1 < 2)}"
  197. assert str(v(1) <= v(2)) == "{(1 <= 2)}"
  198. assert str(v(1) > v(2)) == "{(1 > 2)}"
  199. assert str(v(1) >= v(2)) == "{(1 >= 2)}"
  200. assert str(v(1) + v(2)) == "{(1 + 2)}"
  201. assert str(v(1) - v(2)) == "{(1 - 2)}"
  202. assert str(v(1) * v(2)) == "{(1 * 2)}"
  203. assert str(v(1) / v(2)) == "{(1 / 2)}"
  204. assert str(v(1) // v(2)) == "{Math.floor(1 / 2)}"
  205. assert str(v(1) % v(2)) == "{(1 % 2)}"
  206. assert str(v(1) ** v(2)) == "{Math.pow(1 , 2)}"
  207. assert str(v(1) & v(2)) == "{(1 && 2)}"
  208. assert str(v(1) | v(2)) == "{(1 || 2)}"
  209. assert str(v([1, 2, 3])[v(0)]) == "{[1, 2, 3].at(0)}"
  210. assert str(v({"a": 1, "b": 2})["a"]) == '{{"a": 1, "b": 2}["a"]}'
  211. assert (
  212. str(BaseVar(_var_name="foo", _var_state="state", _var_type=TestObj).bar)
  213. == "{state.foo.bar}"
  214. )
  215. assert str(abs(v(1))) == "{Math.abs(1)}"
  216. assert str(v([1, 2, 3]).length()) == "{[1, 2, 3].length}"
  217. assert str(v([1, 2]) + v([3, 4])) == "{spreadArraysOrObjects([1, 2] , [3, 4])}"
  218. # Tests for reverse operation
  219. assert str(v([1, 2, 3]).reverse()) == "{[...[1, 2, 3]].reverse()}"
  220. assert str(v(["1", "2", "3"]).reverse()) == '{[...["1", "2", "3"]].reverse()}'
  221. assert (
  222. str(BaseVar(_var_name="foo", _var_state="state", _var_type=list).reverse())
  223. == "{[...state.foo].reverse()}"
  224. )
  225. assert (
  226. str(BaseVar(_var_name="foo", _var_type=list).reverse())
  227. == "{[...foo].reverse()}"
  228. )
  229. @pytest.mark.parametrize(
  230. "var, expected",
  231. [
  232. (v([1, 2, 3]), "[1, 2, 3]"),
  233. (v(["1", "2", "3"]), '["1", "2", "3"]'),
  234. (BaseVar(_var_name="foo", _var_state="state", _var_type=list), "state.foo"),
  235. (BaseVar(_var_name="foo", _var_type=list), "foo"),
  236. (v((1, 2, 3)), "[1, 2, 3]"),
  237. (v(("1", "2", "3")), '["1", "2", "3"]'),
  238. (BaseVar(_var_name="foo", _var_state="state", _var_type=tuple), "state.foo"),
  239. (BaseVar(_var_name="foo", _var_type=tuple), "foo"),
  240. ],
  241. )
  242. def test_list_tuple_contains(var, expected):
  243. assert str(var.contains(1)) == f"{{{expected}.includes(1)}}"
  244. assert str(var.contains("1")) == f'{{{expected}.includes("1")}}'
  245. assert str(var.contains(v(1))) == f"{{{expected}.includes(1)}}"
  246. assert str(var.contains(v("1"))) == f'{{{expected}.includes("1")}}'
  247. other_state_var = BaseVar(_var_name="other", _var_state="state", _var_type=str)
  248. other_var = BaseVar(_var_name="other", _var_type=str)
  249. assert str(var.contains(other_state_var)) == f"{{{expected}.includes(state.other)}}"
  250. assert str(var.contains(other_var)) == f"{{{expected}.includes(other)}}"
  251. @pytest.mark.parametrize(
  252. "var, expected",
  253. [
  254. (v("123"), json.dumps("123")),
  255. (BaseVar(_var_name="foo", _var_state="state", _var_type=str), "state.foo"),
  256. (BaseVar(_var_name="foo", _var_type=str), "foo"),
  257. ],
  258. )
  259. def test_str_contains(var, expected):
  260. assert str(var.contains("1")) == f'{{{expected}.includes("1")}}'
  261. assert str(var.contains(v("1"))) == f'{{{expected}.includes("1")}}'
  262. other_state_var = BaseVar(_var_name="other", _var_state="state", _var_type=str)
  263. other_var = BaseVar(_var_name="other", _var_type=str)
  264. assert str(var.contains(other_state_var)) == f"{{{expected}.includes(state.other)}}"
  265. assert str(var.contains(other_var)) == f"{{{expected}.includes(other)}}"
  266. @pytest.mark.parametrize(
  267. "var, expected",
  268. [
  269. (v({"a": 1, "b": 2}), '{"a": 1, "b": 2}'),
  270. (BaseVar(_var_name="foo", _var_state="state", _var_type=dict), "state.foo"),
  271. (BaseVar(_var_name="foo", _var_type=dict), "foo"),
  272. ],
  273. )
  274. def test_dict_contains(var, expected):
  275. assert str(var.contains(1)) == f"{{{expected}.hasOwnProperty(1)}}"
  276. assert str(var.contains("1")) == f'{{{expected}.hasOwnProperty("1")}}'
  277. assert str(var.contains(v(1))) == f"{{{expected}.hasOwnProperty(1)}}"
  278. assert str(var.contains(v("1"))) == f'{{{expected}.hasOwnProperty("1")}}'
  279. other_state_var = BaseVar(_var_name="other", _var_state="state", _var_type=str)
  280. other_var = BaseVar(_var_name="other", _var_type=str)
  281. assert (
  282. str(var.contains(other_state_var))
  283. == f"{{{expected}.hasOwnProperty(state.other)}}"
  284. )
  285. assert str(var.contains(other_var)) == f"{{{expected}.hasOwnProperty(other)}}"
  286. @pytest.mark.parametrize(
  287. "var",
  288. [
  289. BaseVar(_var_name="list", _var_type=List[int]),
  290. BaseVar(_var_name="tuple", _var_type=Tuple[int, int]),
  291. BaseVar(_var_name="str", _var_type=str),
  292. ],
  293. )
  294. def test_var_indexing_lists(var):
  295. """Test that we can index into str, list or tuple vars.
  296. Args:
  297. var : The str, list or tuple base var.
  298. """
  299. # Test basic indexing.
  300. assert str(var[0]) == f"{{{var._var_name}.at(0)}}"
  301. assert str(var[1]) == f"{{{var._var_name}.at(1)}}"
  302. # Test negative indexing.
  303. assert str(var[-1]) == f"{{{var._var_name}.at(-1)}}"
  304. @pytest.mark.parametrize(
  305. "var, index",
  306. [
  307. (BaseVar(_var_name="lst", _var_type=List[int]), [1, 2]),
  308. (BaseVar(_var_name="lst", _var_type=List[int]), {"name": "dict"}),
  309. (BaseVar(_var_name="lst", _var_type=List[int]), {"set"}),
  310. (
  311. BaseVar(_var_name="lst", _var_type=List[int]),
  312. (
  313. 1,
  314. 2,
  315. ),
  316. ),
  317. (BaseVar(_var_name="lst", _var_type=List[int]), 1.5),
  318. (BaseVar(_var_name="lst", _var_type=List[int]), "str"),
  319. (
  320. BaseVar(_var_name="lst", _var_type=List[int]),
  321. BaseVar(_var_name="string_var", _var_type=str),
  322. ),
  323. (
  324. BaseVar(_var_name="lst", _var_type=List[int]),
  325. BaseVar(_var_name="float_var", _var_type=float),
  326. ),
  327. (
  328. BaseVar(_var_name="lst", _var_type=List[int]),
  329. BaseVar(_var_name="list_var", _var_type=List[int]),
  330. ),
  331. (
  332. BaseVar(_var_name="lst", _var_type=List[int]),
  333. BaseVar(_var_name="set_var", _var_type=Set[str]),
  334. ),
  335. (
  336. BaseVar(_var_name="lst", _var_type=List[int]),
  337. BaseVar(_var_name="dict_var", _var_type=Dict[str, str]),
  338. ),
  339. (BaseVar(_var_name="str", _var_type=str), [1, 2]),
  340. (BaseVar(_var_name="lst", _var_type=str), {"name": "dict"}),
  341. (BaseVar(_var_name="lst", _var_type=str), {"set"}),
  342. (
  343. BaseVar(_var_name="lst", _var_type=str),
  344. BaseVar(_var_name="string_var", _var_type=str),
  345. ),
  346. (
  347. BaseVar(_var_name="lst", _var_type=str),
  348. BaseVar(_var_name="float_var", _var_type=float),
  349. ),
  350. (BaseVar(_var_name="str", _var_type=Tuple[str]), [1, 2]),
  351. (BaseVar(_var_name="lst", _var_type=Tuple[str]), {"name": "dict"}),
  352. (BaseVar(_var_name="lst", _var_type=Tuple[str]), {"set"}),
  353. (
  354. BaseVar(_var_name="lst", _var_type=Tuple[str]),
  355. BaseVar(_var_name="string_var", _var_type=str),
  356. ),
  357. (
  358. BaseVar(_var_name="lst", _var_type=Tuple[str]),
  359. BaseVar(_var_name="float_var", _var_type=float),
  360. ),
  361. ],
  362. )
  363. def test_var_unsupported_indexing_lists(var, index):
  364. """Test unsupported indexing throws a type error.
  365. Args:
  366. var: The base var.
  367. index: The base var index.
  368. """
  369. with pytest.raises(TypeError):
  370. var[index]
  371. @pytest.mark.parametrize(
  372. "var",
  373. [
  374. BaseVar(_var_name="lst", _var_type=List[int]),
  375. BaseVar(_var_name="tuple", _var_type=Tuple[int, int]),
  376. BaseVar(_var_name="str", _var_type=str),
  377. ],
  378. )
  379. def test_var_list_slicing(var):
  380. """Test that we can slice into str, list or tuple vars.
  381. Args:
  382. var : The str, list or tuple base var.
  383. """
  384. assert str(var[:1]) == f"{{{var._var_name}.slice(0, 1)}}"
  385. assert str(var[:1]) == f"{{{var._var_name}.slice(0, 1)}}"
  386. assert str(var[:]) == f"{{{var._var_name}.slice(0, undefined)}}"
  387. def test_dict_indexing():
  388. """Test that we can index into dict vars."""
  389. dct = BaseVar(_var_name="dct", _var_type=Dict[str, int])
  390. # Check correct indexing.
  391. assert str(dct["a"]) == '{dct["a"]}'
  392. assert str(dct["asdf"]) == '{dct["asdf"]}'
  393. @pytest.mark.parametrize(
  394. "var, index",
  395. [
  396. (
  397. BaseVar(_var_name="dict", _var_type=Dict[str, str]),
  398. [1, 2],
  399. ),
  400. (
  401. BaseVar(_var_name="dict", _var_type=Dict[str, str]),
  402. {"name": "dict"},
  403. ),
  404. (
  405. BaseVar(_var_name="dict", _var_type=Dict[str, str]),
  406. {"set"},
  407. ),
  408. (
  409. BaseVar(_var_name="dict", _var_type=Dict[str, str]),
  410. (
  411. 1,
  412. 2,
  413. ),
  414. ),
  415. (
  416. BaseVar(_var_name="lst", _var_type=Dict[str, str]),
  417. BaseVar(_var_name="list_var", _var_type=List[int]),
  418. ),
  419. (
  420. BaseVar(_var_name="lst", _var_type=Dict[str, str]),
  421. BaseVar(_var_name="set_var", _var_type=Set[str]),
  422. ),
  423. (
  424. BaseVar(_var_name="lst", _var_type=Dict[str, str]),
  425. BaseVar(_var_name="dict_var", _var_type=Dict[str, str]),
  426. ),
  427. (
  428. BaseVar(_var_name="df", _var_type=DataFrame),
  429. [1, 2],
  430. ),
  431. (
  432. BaseVar(_var_name="df", _var_type=DataFrame),
  433. {"name": "dict"},
  434. ),
  435. (
  436. BaseVar(_var_name="df", _var_type=DataFrame),
  437. {"set"},
  438. ),
  439. (
  440. BaseVar(_var_name="df", _var_type=DataFrame),
  441. (
  442. 1,
  443. 2,
  444. ),
  445. ),
  446. (
  447. BaseVar(_var_name="df", _var_type=DataFrame),
  448. BaseVar(_var_name="list_var", _var_type=List[int]),
  449. ),
  450. (
  451. BaseVar(_var_name="df", _var_type=DataFrame),
  452. BaseVar(_var_name="set_var", _var_type=Set[str]),
  453. ),
  454. (
  455. BaseVar(_var_name="df", _var_type=DataFrame),
  456. BaseVar(_var_name="dict_var", _var_type=Dict[str, str]),
  457. ),
  458. ],
  459. )
  460. def test_var_unsupported_indexing_dicts(var, index):
  461. """Test unsupported indexing throws a type error.
  462. Args:
  463. var: The base var.
  464. index: The base var index.
  465. """
  466. with pytest.raises(TypeError):
  467. var[index]
  468. @pytest.mark.parametrize(
  469. "fixture,full_name",
  470. [
  471. ("ParentState", "parent_state.var_without_annotation"),
  472. ("ChildState", "parent_state.child_state.var_without_annotation"),
  473. (
  474. "GrandChildState",
  475. "parent_state.child_state.grand_child_state.var_without_annotation",
  476. ),
  477. ("StateWithAnyVar", "state_with_any_var.var_without_annotation"),
  478. ],
  479. )
  480. def test_computed_var_without_annotation_error(request, fixture, full_name):
  481. """Test that a type error is thrown when an attribute of a computed var is
  482. accessed without annotating the computed var.
  483. Args:
  484. request: Fixture Request.
  485. fixture: The state fixture.
  486. full_name: The full name of the state var.
  487. """
  488. with pytest.raises(TypeError) as err:
  489. state = request.getfixturevalue(fixture)
  490. state.var_without_annotation.foo
  491. assert (
  492. err.value.args[0]
  493. == f"You must provide an annotation for the state var `{full_name}`. Annotation cannot be `typing.Any`"
  494. )
  495. @pytest.mark.parametrize(
  496. "fixture,full_name",
  497. [
  498. (
  499. "StateWithCorrectVarAnnotation",
  500. "state_with_correct_var_annotation.var_with_annotation",
  501. ),
  502. (
  503. "StateWithWrongVarAnnotation",
  504. "state_with_wrong_var_annotation.var_with_annotation",
  505. ),
  506. ],
  507. )
  508. def test_computed_var_with_annotation_error(request, fixture, full_name):
  509. """Test that an Attribute error is thrown when a non-existent attribute of an annotated computed var is
  510. accessed or when the wrong annotation is provided to a computed var.
  511. Args:
  512. request: Fixture Request.
  513. fixture: The state fixture.
  514. full_name: The full name of the state var.
  515. """
  516. with pytest.raises(AttributeError) as err:
  517. state = request.getfixturevalue(fixture)
  518. state.var_with_annotation.foo
  519. assert (
  520. err.value.args[0]
  521. == f"The State var `{full_name}` has no attribute 'foo' or may have been annotated wrongly."
  522. )
  523. @pytest.mark.parametrize(
  524. "import_var,expected",
  525. zip(
  526. test_import_vars,
  527. [
  528. "DataGrid",
  529. "DataGrid as Grid",
  530. ],
  531. ),
  532. )
  533. def test_import_var(import_var, expected):
  534. """Test that the import var name is computed correctly.
  535. Args:
  536. import_var: The import var.
  537. expected: expected name
  538. """
  539. assert import_var.name == expected
  540. @pytest.mark.parametrize(
  541. "out, expected",
  542. [
  543. (f"{BaseVar(_var_name='var', _var_type=str)}", "${var}"),
  544. (
  545. f"testing f-string with {BaseVar(_var_name='myvar', _var_state='state', _var_type=int)}",
  546. "testing f-string with ${state.myvar}",
  547. ),
  548. (
  549. f"testing local f-string {BaseVar(_var_name='x', _var_is_local=True, _var_type=str)}",
  550. "testing local f-string x",
  551. ),
  552. ],
  553. )
  554. def test_fstrings(out, expected):
  555. assert out == expected
  556. @pytest.mark.parametrize(
  557. "var",
  558. [
  559. BaseVar(_var_name="var", _var_type=int),
  560. BaseVar(_var_name="var", _var_type=float),
  561. BaseVar(_var_name="var", _var_type=str),
  562. BaseVar(_var_name="var", _var_type=bool),
  563. BaseVar(_var_name="var", _var_type=dict),
  564. BaseVar(_var_name="var", _var_type=tuple),
  565. BaseVar(_var_name="var", _var_type=set),
  566. BaseVar(_var_name="var", _var_type=None),
  567. ],
  568. )
  569. def test_unsupported_types_for_reverse(var):
  570. """Test that unsupported types for reverse throw a type error.
  571. Args:
  572. var: The base var.
  573. """
  574. with pytest.raises(TypeError) as err:
  575. var.reverse()
  576. assert err.value.args[0] == f"Cannot reverse non-list var var."
  577. @pytest.mark.parametrize(
  578. "var",
  579. [
  580. BaseVar(_var_name="var", _var_type=int),
  581. BaseVar(_var_name="var", _var_type=float),
  582. BaseVar(_var_name="var", _var_type=bool),
  583. BaseVar(_var_name="var", _var_type=set),
  584. BaseVar(_var_name="var", _var_type=None),
  585. ],
  586. )
  587. def test_unsupported_types_for_contains(var):
  588. """Test that unsupported types for contains throw a type error.
  589. Args:
  590. var: The base var.
  591. """
  592. with pytest.raises(TypeError) as err:
  593. assert var.contains(1)
  594. assert (
  595. err.value.args[0]
  596. == f"Var var of type {var._var_type} does not support contains check."
  597. )
  598. @pytest.mark.parametrize(
  599. "other",
  600. [
  601. BaseVar(_var_name="other", _var_type=int),
  602. BaseVar(_var_name="other", _var_type=float),
  603. BaseVar(_var_name="other", _var_type=bool),
  604. BaseVar(_var_name="other", _var_type=list),
  605. BaseVar(_var_name="other", _var_type=dict),
  606. BaseVar(_var_name="other", _var_type=tuple),
  607. BaseVar(_var_name="other", _var_type=set),
  608. ],
  609. )
  610. def test_unsupported_types_for_string_contains(other):
  611. with pytest.raises(TypeError) as err:
  612. assert BaseVar(_var_name="var", _var_type=str).contains(other)
  613. assert (
  614. err.value.args[0]
  615. == f"'in <string>' requires string as left operand, not {other._var_type}"
  616. )
  617. def test_unsupported_default_contains():
  618. with pytest.raises(TypeError) as err:
  619. assert 1 in BaseVar(_var_name="var", _var_type=str)
  620. assert (
  621. err.value.args[0]
  622. == "'in' operator not supported for Var types, use Var.contains() instead."
  623. )
  624. @pytest.mark.parametrize(
  625. "operand1_var,operand2_var,operators",
  626. [
  627. (
  628. Var.create(10),
  629. Var.create(5),
  630. [
  631. "+",
  632. "-",
  633. "/",
  634. "//",
  635. "*",
  636. "%",
  637. "**",
  638. ">",
  639. "<",
  640. "<=",
  641. ">=",
  642. "|",
  643. "&",
  644. ],
  645. ),
  646. (
  647. Var.create(10.5),
  648. Var.create(5),
  649. ["+", "-", "/", "//", "*", "%", "**", ">", "<", "<=", ">="],
  650. ),
  651. (
  652. Var.create(5),
  653. Var.create(True),
  654. [
  655. "+",
  656. "-",
  657. "/",
  658. "//",
  659. "*",
  660. "%",
  661. "**",
  662. ">",
  663. "<",
  664. "<=",
  665. ">=",
  666. "|",
  667. "&",
  668. ],
  669. ),
  670. (
  671. Var.create(10.5),
  672. Var.create(5.5),
  673. ["+", "-", "/", "//", "*", "%", "**", ">", "<", "<=", ">="],
  674. ),
  675. (
  676. Var.create(10.5),
  677. Var.create(True),
  678. ["+", "-", "/", "//", "*", "%", "**", ">", "<", "<=", ">="],
  679. ),
  680. (Var.create("10"), Var.create("5"), ["+", ">", "<", "<=", ">="]),
  681. (Var.create([10, 20]), Var.create([5, 6]), ["+", ">", "<", "<=", ">="]),
  682. (Var.create([10, 20]), Var.create(5), ["*"]),
  683. (Var.create([10, 20]), Var.create(True), ["*"]),
  684. (
  685. Var.create(True),
  686. Var.create(True),
  687. [
  688. "+",
  689. "-",
  690. "/",
  691. "//",
  692. "*",
  693. "%",
  694. "**",
  695. ">",
  696. "<",
  697. "<=",
  698. ">=",
  699. "|",
  700. "&",
  701. ],
  702. ),
  703. ],
  704. )
  705. def test_valid_var_operations(operand1_var: Var, operand2_var, operators: List[str]):
  706. """Test that operations do not raise a TypeError.
  707. Args:
  708. operand1_var: left operand.
  709. operand2_var: right operand.
  710. operators: list of supported operators.
  711. """
  712. for operator in operators:
  713. operand1_var.operation(op=operator, other=operand2_var)
  714. operand1_var.operation(op=operator, other=operand2_var, flip=True)
  715. @pytest.mark.parametrize(
  716. "operand1_var,operand2_var,operators",
  717. [
  718. (
  719. Var.create(10),
  720. Var.create(5),
  721. [
  722. "^",
  723. "<<",
  724. ">>",
  725. ],
  726. ),
  727. (
  728. Var.create(10.5),
  729. Var.create(5),
  730. [
  731. "|",
  732. "^",
  733. "<<",
  734. ">>",
  735. "&",
  736. ],
  737. ),
  738. (
  739. Var.create(10.5),
  740. Var.create(True),
  741. [
  742. "|",
  743. "^",
  744. "<<",
  745. ">>",
  746. "&",
  747. ],
  748. ),
  749. (
  750. Var.create(10.5),
  751. Var.create(5.5),
  752. [
  753. "|",
  754. "^",
  755. "<<",
  756. ">>",
  757. "&",
  758. ],
  759. ),
  760. (
  761. Var.create("10"),
  762. Var.create("5"),
  763. [
  764. "-",
  765. "/",
  766. "//",
  767. "*",
  768. "%",
  769. "**",
  770. "|",
  771. "^",
  772. "<<",
  773. ">>",
  774. "&",
  775. ],
  776. ),
  777. (
  778. Var.create([10, 20]),
  779. Var.create([5, 6]),
  780. [
  781. "-",
  782. "/",
  783. "//",
  784. "*",
  785. "%",
  786. "**",
  787. "|",
  788. "^",
  789. "<<",
  790. ">>",
  791. "&",
  792. ],
  793. ),
  794. (
  795. Var.create([10, 20]),
  796. Var.create(5),
  797. [
  798. "+",
  799. "-",
  800. "/",
  801. "//",
  802. "%",
  803. "**",
  804. ">",
  805. "<",
  806. "<=",
  807. ">=",
  808. "|",
  809. "^",
  810. "<<",
  811. ">>",
  812. "&",
  813. ],
  814. ),
  815. (
  816. Var.create([10, 20]),
  817. Var.create(True),
  818. [
  819. "+",
  820. "-",
  821. "/",
  822. "//",
  823. "%",
  824. "**",
  825. ">",
  826. "<",
  827. "<=",
  828. ">=",
  829. "|",
  830. "^",
  831. "<<",
  832. ">>",
  833. "&",
  834. ],
  835. ),
  836. (
  837. Var.create([10, 20]),
  838. Var.create("5"),
  839. [
  840. "+",
  841. "-",
  842. "/",
  843. "//",
  844. "*",
  845. "%",
  846. "**",
  847. ">",
  848. "<",
  849. "<=",
  850. ">=",
  851. "|",
  852. "^",
  853. "<<",
  854. ">>",
  855. "&",
  856. ],
  857. ),
  858. (
  859. Var.create([10, 20]),
  860. Var.create({"key": "value"}),
  861. [
  862. "+",
  863. "-",
  864. "/",
  865. "//",
  866. "*",
  867. "%",
  868. "**",
  869. ">",
  870. "<",
  871. "<=",
  872. ">=",
  873. "|",
  874. "^",
  875. "<<",
  876. ">>",
  877. "&",
  878. ],
  879. ),
  880. (
  881. Var.create([10, 20]),
  882. Var.create(5.5),
  883. [
  884. "+",
  885. "-",
  886. "/",
  887. "//",
  888. "*",
  889. "%",
  890. "**",
  891. ">",
  892. "<",
  893. "<=",
  894. ">=",
  895. "|",
  896. "^",
  897. "<<",
  898. ">>",
  899. "&",
  900. ],
  901. ),
  902. (
  903. Var.create({"key": "value"}),
  904. Var.create({"another_key": "another_value"}),
  905. [
  906. "+",
  907. "-",
  908. "/",
  909. "//",
  910. "*",
  911. "%",
  912. "**",
  913. ">",
  914. "<",
  915. "<=",
  916. ">=",
  917. "|",
  918. "^",
  919. "<<",
  920. ">>",
  921. "&",
  922. ],
  923. ),
  924. (
  925. Var.create({"key": "value"}),
  926. Var.create(5),
  927. [
  928. "+",
  929. "-",
  930. "/",
  931. "//",
  932. "*",
  933. "%",
  934. "**",
  935. ">",
  936. "<",
  937. "<=",
  938. ">=",
  939. "|",
  940. "^",
  941. "<<",
  942. ">>",
  943. "&",
  944. ],
  945. ),
  946. (
  947. Var.create({"key": "value"}),
  948. Var.create(True),
  949. [
  950. "+",
  951. "-",
  952. "/",
  953. "//",
  954. "*",
  955. "%",
  956. "**",
  957. ">",
  958. "<",
  959. "<=",
  960. ">=",
  961. "|",
  962. "^",
  963. "<<",
  964. ">>",
  965. "&",
  966. ],
  967. ),
  968. (
  969. Var.create({"key": "value"}),
  970. Var.create(5.5),
  971. [
  972. "+",
  973. "-",
  974. "/",
  975. "//",
  976. "*",
  977. "%",
  978. "**",
  979. ">",
  980. "<",
  981. "<=",
  982. ">=",
  983. "|",
  984. "^",
  985. "<<",
  986. ">>",
  987. "&",
  988. ],
  989. ),
  990. (
  991. Var.create({"key": "value"}),
  992. Var.create("5"),
  993. [
  994. "+",
  995. "-",
  996. "/",
  997. "//",
  998. "*",
  999. "%",
  1000. "**",
  1001. ">",
  1002. "<",
  1003. "<=",
  1004. ">=",
  1005. "|",
  1006. "^",
  1007. "<<",
  1008. ">>",
  1009. "&",
  1010. ],
  1011. ),
  1012. ],
  1013. )
  1014. def test_invalid_var_operations(operand1_var: Var, operand2_var, operators: List[str]):
  1015. for operator in operators:
  1016. with pytest.raises(TypeError):
  1017. operand1_var.operation(op=operator, other=operand2_var)
  1018. with pytest.raises(TypeError):
  1019. operand1_var.operation(op=operator, other=operand2_var, flip=True)