Преглед на файлове

Support backend-only state vars (#390)

Thomas Brandého преди 2 години
родител
ревизия
4971f6d814
променени са 3 файла, в които са добавени 39 реда и са изтрити 0 реда
  1. 15 0
      pynecone/state.py
  2. 12 0
      pynecone/utils.py
  3. 12 0
      tests/test_utils.py

+ 15 - 0
pynecone/state.py

@@ -33,6 +33,9 @@ class State(Base, ABC):
     # Vars inherited by the parent state.
     # Vars inherited by the parent state.
     inherited_vars: ClassVar[Dict[str, Var]] = {}
     inherited_vars: ClassVar[Dict[str, Var]] = {}
 
 
+    # Backend vars that are never sent to the client.
+    backend_vars: ClassVar[Dict[str, Any]] = {}
+
     # The parent state.
     # The parent state.
     parent_state: Optional[State] = None
     parent_state: Optional[State] = None
 
 
@@ -117,6 +120,12 @@ class State(Base, ABC):
         if parent_state is not None:
         if parent_state is not None:
             cls.inherited_vars = parent_state.vars
             cls.inherited_vars = parent_state.vars
 
 
+        cls.backend_vars = {
+            name: value
+            for name, value in cls.__dict__.items()
+            if utils.is_backend_variable(name)
+        }
+
         # Set the base and computed vars.
         # Set the base and computed vars.
         skip_vars = set(cls.inherited_vars) | {
         skip_vars = set(cls.inherited_vars) | {
             "parent_state",
             "parent_state",
@@ -409,6 +418,8 @@ class State(Base, ABC):
         # Get the var from the parent state.
         # Get the var from the parent state.
         if name in super().__getattribute__("inherited_vars"):
         if name in super().__getattribute__("inherited_vars"):
             return getattr(super().__getattribute__("parent_state"), name)
             return getattr(super().__getattribute__("parent_state"), name)
+        elif name in super().__getattribute__("backend_vars"):
+            return super().__getattribute__("backend_vars").__getitem__(name)
         return super().__getattribute__(name)
         return super().__getattribute__(name)
 
 
     def __setattr__(self, name: str, value: Any):
     def __setattr__(self, name: str, value: Any):
@@ -425,6 +436,10 @@ class State(Base, ABC):
             setattr(self.parent_state, name, value)
             setattr(self.parent_state, name, value)
             return
             return
 
 
+        if utils.is_backend_variable(name):
+            self.backend_vars.__setitem__(name, value)
+            return
+
         # Set the attribute.
         # Set the attribute.
         super().__setattr__(name, value)
         super().__setattr__(name, value)
 
 

+ 12 - 0
pynecone/utils.py

@@ -1251,5 +1251,17 @@ def get_redis() -> Optional[Redis]:
     return Redis(host=redis_url, port=int(redis_port), db=0)
     return Redis(host=redis_url, port=int(redis_port), db=0)
 
 
 
 
+def is_backend_variable(name: str) -> bool:
+    """Check if this variable name correspond to a backend variable.
+
+    Args:
+        name (str): The name of the variable to check
+
+    Returns:
+        bool: The result of the check
+    """
+    return name.startswith("_") and not name.startswith("__")
+
+
 # Store this here for performance.
 # Store this here for performance.
 StateBases = get_base_class(StateVar)
 StateBases = get_base_class(StateVar)

+ 12 - 0
tests/test_utils.py

@@ -245,3 +245,15 @@ def test_setup_frontend(tmp_path, mocker):
     assert web_folder.exists()
     assert web_folder.exists()
     assert web_public_folder.exists()
     assert web_public_folder.exists()
     assert (web_public_folder / "favicon.ico").exists()
     assert (web_public_folder / "favicon.ico").exists()
+
+
+@pytest.mark.parametrize(
+    "input, output",
+    [
+        ("_hidden", True),
+        ("not_hidden", False),
+        ("__dundermethod__", False),
+    ],
+)
+def test_is_backend_variable(input, output):
+    assert utils.is_backend_variable(input) == output