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

auto enable /_upload endpoint only if Upload component is used (#2430)

benedikt-bartscher преди 1 година
родител
ревизия
0b1b8ee639
променени са 4 файла, в които са добавени 43 реда и са изтрити 12 реда
  1. 5 2
      reflex/app.py
  2. 19 2
      reflex/components/core/upload.py
  3. 6 7
      reflex/components/core/upload.pyi
  4. 13 1
      scripts/pyi_generator.py

+ 5 - 2
reflex/app.py

@@ -43,6 +43,7 @@ from reflex.components.core.client_side_routing import (
     Default404Page,
     wait_for_client_redirect,
 )
+from reflex.components.core.upload import UploadFilesProvider
 from reflex.config import get_config
 from reflex.event import Event, EventHandler, EventSpec
 from reflex.middleware import HydrateMiddleware, Middleware
@@ -180,7 +181,6 @@ class App(Base):
         # Set up the API.
         self.api = FastAPI()
         self.add_cors()
-        self.add_default_endpoints()
 
         if self.state:
             # Set up the state manager.
@@ -242,7 +242,8 @@ class App(Base):
         self.api.get(str(constants.Endpoint.PING))(ping)
 
         # To upload files.
-        self.api.post(str(constants.Endpoint.UPLOAD))(upload(self))
+        if UploadFilesProvider.is_used:
+            self.api.post(str(constants.Endpoint.UPLOAD))(upload(self))
 
     def add_cors(self):
         """Add CORS middleware to the app."""
@@ -800,6 +801,8 @@ class App(Base):
             for future in concurrent.futures.as_completed(write_page_futures):
                 future.result()
 
+        self.add_default_endpoints()
+
     @contextlib.asynccontextmanager
     async def modify_state(self, token: str) -> AsyncIterator[BaseState]:
         """Modify the state out of band.

+ 19 - 2
reflex/components/core/upload.py

@@ -1,7 +1,7 @@
 """A file upload component."""
 from __future__ import annotations
 
-from typing import Any, Dict, List, Optional, Union
+from typing import Any, ClassVar, Dict, List, Optional, Union
 
 from reflex import constants
 from reflex.components.chakra.forms.input import Input
@@ -98,6 +98,23 @@ class UploadFilesProvider(Component):
     library = f"/{Dirs.CONTEXTS_PATH}"
     tag = "UploadFilesProvider"
 
+    is_used: ClassVar[bool] = False
+
+    @classmethod
+    def create(cls, *children, **props) -> Component:
+        """Create an UploadFilesProvider component.
+
+        Args:
+            *children: The children of the component.
+            **props: The properties of the component.
+
+        Returns:
+            The UploadFilesProvider component.
+        """
+        cls.is_used = True
+
+        return super().create(*children, **props)
+
 
 class Upload(Component):
     """A file upload component."""
@@ -192,5 +209,5 @@ class Upload(Component):
     @staticmethod
     def _get_app_wrap_components() -> dict[tuple[int, str], Component]:
         return {
-            (5, "UploadFilesProvider"): UploadFilesProvider(),
+            (5, "UploadFilesProvider"): UploadFilesProvider.create(),
         }

+ 6 - 7
reflex/components/core/upload.pyi

@@ -7,7 +7,7 @@ from typing import Any, Dict, Literal, Optional, Union, overload
 from reflex.vars import Var, BaseVar, ComputedVar
 from reflex.event import EventChain, EventHandler, EventSpec
 from reflex.style import Style
-from typing import Any, Dict, List, Optional, Union
+from typing import Any, ClassVar, Dict, List, Optional, Union
 from reflex import constants
 from reflex.components.chakra.forms.input import Input
 from reflex.components.chakra.layout.box import Box
@@ -29,6 +29,8 @@ def clear_selected_files(id_: str = DEFAULT_UPLOAD_ID) -> EventSpec: ...
 def cancel_upload(upload_id: str) -> EventSpec: ...
 
 class UploadFilesProvider(Component):
+    is_used: ClassVar[bool] = False
+
     @overload
     @classmethod
     def create(  # type: ignore
@@ -87,7 +89,7 @@ class UploadFilesProvider(Component):
         ] = None,
         **props
     ) -> "UploadFilesProvider":
-        """Create the component.
+        """Create an UploadFilesProvider component.
 
         Args:
             *children: The children of the component.
@@ -97,13 +99,10 @@ class UploadFilesProvider(Component):
             class_name: The class name for the component.
             autofocus: Whether the component should take the focus once the page is loaded
             custom_attrs: custom attribute
-            **props: The props of the component.
+            **props: The properties of the component.
 
         Returns:
-            The component.
-
-        Raises:
-            TypeError: If an invalid child is passed.
+            The UploadFilesProvider component.
         """
         ...
 

+ 13 - 1
scripts/pyi_generator.py

@@ -245,7 +245,12 @@ def _extract_class_props_as_ast_nodes(
         # Import from the target class to ensure type hints are resolvable.
         exec(f"from {target_class.__module__} import *", type_hint_globals)
         for name, value in target_class.__annotations__.items():
-            if name in spec.kwonlyargs or name in EXCLUDED_PROPS or name in all_props:
+            if (
+                name in spec.kwonlyargs
+                or name in EXCLUDED_PROPS
+                or name in all_props
+                or (isinstance(value, str) and "ClassVar" in value)
+            ):
                 continue
             all_props.append(name)
 
@@ -559,6 +564,13 @@ class StubGenerator(ast.NodeTransformer):
         Returns:
             The modified AnnAssign node (or None).
         """
+        # skip ClassVars
+        if (
+            isinstance(node.annotation, ast.Subscript)
+            and isinstance(node.annotation.value, ast.Name)
+            and node.annotation.value.id == "ClassVar"
+        ):
+            return node
         if isinstance(node.target, ast.Name) and node.target.id.startswith("_"):
             return None
         if self.current_class in self.classes: