mutation.py 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. """Test states for mutable vars."""
  2. from sqlalchemy import ARRAY, JSON, String
  3. from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
  4. import reflex as rx
  5. from reflex.state import BaseState
  6. from reflex.utils.serializers import serializer
  7. class DictMutationTestState(BaseState):
  8. """A state for testing ReflexDict mutation."""
  9. # plain dict
  10. details = {"name": "Tommy"}
  11. def add_age(self):
  12. """Add an age to the dict."""
  13. self.details.update({"age": 20}) # pyright: ignore [reportCallIssue, reportArgumentType]
  14. def change_name(self):
  15. """Change the name in the dict."""
  16. self.details["name"] = "Jenny"
  17. def remove_last_detail(self):
  18. """Remove the last item in the dict."""
  19. self.details.popitem()
  20. def clear_details(self):
  21. """Clear the dict."""
  22. self.details.clear()
  23. def remove_name(self):
  24. """Remove the name from the dict."""
  25. del self.details["name"]
  26. def pop_out_age(self):
  27. """Pop out the age from the dict."""
  28. self.details.pop("age")
  29. # dict in list
  30. address = [{"home": "home address"}, {"work": "work address"}]
  31. def remove_home_address(self):
  32. """Remove the home address from dict in the list."""
  33. self.address[0].pop("home")
  34. def add_street_to_home_address(self):
  35. """Set street key in the dict in the list."""
  36. self.address[0]["street"] = "street address"
  37. # nested dict
  38. friend_in_nested_dict = {"name": "Nikhil", "friend": {"name": "Alek"}}
  39. def change_friend_name(self):
  40. """Change the friend's name in the nested dict."""
  41. self.friend_in_nested_dict["friend"]["name"] = "Tommy"
  42. def remove_friend(self):
  43. """Remove the friend from the nested dict."""
  44. self.friend_in_nested_dict.pop("friend")
  45. def add_friend_age(self):
  46. """Add an age to the friend in the nested dict."""
  47. self.friend_in_nested_dict["friend"]["age"] = 30
  48. class ListMutationTestState(BaseState):
  49. """A state for testing ReflexList mutation."""
  50. # plain list
  51. plain_friends = ["Tommy"]
  52. def make_friend(self):
  53. """Add a friend to the list."""
  54. self.plain_friends.append("another-fd")
  55. def change_first_friend(self):
  56. """Change the first friend in the list."""
  57. self.plain_friends[0] = "Jenny"
  58. def unfriend_all_friends(self):
  59. """Unfriend all friends in the list."""
  60. self.plain_friends.clear()
  61. def unfriend_first_friend(self):
  62. """Unfriend the first friend in the list."""
  63. del self.plain_friends[0]
  64. def remove_last_friend(self):
  65. """Remove the last friend in the list."""
  66. self.plain_friends.pop()
  67. def make_friends_with_colleagues(self):
  68. """Add list of friends to the list."""
  69. colleagues = ["Peter", "Jimmy"]
  70. self.plain_friends.extend(colleagues)
  71. def remove_tommy(self):
  72. """Remove Tommy from the list."""
  73. self.plain_friends.remove("Tommy")
  74. # list in dict
  75. friends_in_dict = {"Tommy": ["Jenny"]}
  76. def remove_jenny_from_tommy(self):
  77. """Remove Jenny from Tommy's friends list."""
  78. self.friends_in_dict["Tommy"].remove("Jenny")
  79. def add_jimmy_to_tommy_friends(self):
  80. """Add Jimmy to Tommy's friends list."""
  81. self.friends_in_dict["Tommy"].append("Jimmy")
  82. def tommy_has_no_fds(self):
  83. """Clear Tommy's friends list."""
  84. self.friends_in_dict["Tommy"].clear()
  85. # nested list
  86. friends_in_nested_list = [["Tommy"], ["Jenny"]]
  87. def remove_first_group(self):
  88. """Remove the first group of friends from the nested list."""
  89. self.friends_in_nested_list.pop(0)
  90. def remove_first_person_from_first_group(self):
  91. """Remove the first person from the first group of friends in the nested list."""
  92. self.friends_in_nested_list[0].pop(0)
  93. def add_jimmy_to_second_group(self):
  94. """Add Jimmy to the second group of friends in the nested list."""
  95. self.friends_in_nested_list[1].append("Jimmy")
  96. class OtherBase(rx.Base):
  97. """A Base model with a str field."""
  98. bar: str = ""
  99. class CustomVar(rx.Base):
  100. """A Base model with multiple fields."""
  101. foo: str = ""
  102. array: list[str] = []
  103. hashmap: dict[str, str] = {}
  104. test_set: set[str] = set()
  105. custom: OtherBase = OtherBase()
  106. class MutableSQLABase(DeclarativeBase):
  107. """SQLAlchemy base model for mutable vars."""
  108. pass
  109. class MutableSQLAModel(MutableSQLABase):
  110. """SQLAlchemy model for mutable vars."""
  111. __tablename__: str = "mutable_test_state"
  112. id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
  113. strlist: Mapped[list[str]] = mapped_column(ARRAY(String))
  114. hashmap: Mapped[dict[str, str]] = mapped_column(JSON)
  115. test_set: Mapped[set[str]] = mapped_column(ARRAY(String))
  116. @serializer
  117. def serialize_mutable_sqla_model(
  118. model: MutableSQLAModel,
  119. ) -> dict[str, list[str] | dict[str, str]]:
  120. """Serialize the MutableSQLAModel.
  121. Args:
  122. model: The MutableSQLAModel instance to serialize.
  123. Returns:
  124. The serialized model.
  125. """
  126. return {"strlist": model.strlist, "hashmap": model.hashmap}
  127. class MutableTestState(BaseState):
  128. """A test state."""
  129. array: list[str | int | list | dict[str, str]] = [
  130. "value",
  131. [1, 2, 3],
  132. {"key": "value"},
  133. ]
  134. hashmap: dict[str, list | str | dict[str, str | dict]] = {
  135. "key": ["list", "of", "values"],
  136. "another_key": "another_value",
  137. "third_key": {"key": "value"},
  138. }
  139. test_set: set[str | int] = {1, 2, 3, 4, "five"}
  140. custom: CustomVar = CustomVar()
  141. _be_custom: CustomVar = CustomVar()
  142. sqla_model: MutableSQLAModel = MutableSQLAModel(
  143. strlist=["a", "b", "c"],
  144. hashmap={"key": "value"},
  145. test_set={"one", "two", "three"},
  146. )
  147. def reassign_mutables(self):
  148. """Assign mutable fields to different values."""
  149. self.array = ["modified_value", [1, 2, 3], {"mod_key": "mod_value"}]
  150. self.hashmap = {
  151. "mod_key": ["list", "of", "values"],
  152. "mod_another_key": "another_value",
  153. "mod_third_key": {"key": "value"},
  154. }
  155. self.test_set = {1, 2, 3, 4, "five"}
  156. self.sqla_model = MutableSQLAModel(
  157. strlist=["d", "e", "f"],
  158. hashmap={"key": "value"},
  159. test_set={"one", "two", "three"},
  160. )