From 2db3f6f3b940e8b916f97400908b8556b3a93736 Mon Sep 17 00:00:00 2001 From: Lendemor Date: Fri, 27 Sep 2024 16:28:18 -0700 Subject: [PATCH] remove all runtime asserts --- reflex/app.py | 14 +++++++++----- reflex/compiler/utils.py | 15 ++++++++++++--- reflex/components/base/meta.py | 8 +++++--- reflex/components/component.py | 6 +++++- reflex/components/core/cond.py | 8 ++++---- reflex/components/gridjs/datatable.py | 3 ++- reflex/components/markdown/markdown.py | 10 +++++++--- reflex/components/markdown/markdown.pyi | 3 +++ reflex/components/tags/iter_tag.py | 6 +++++- reflex/event.py | 6 +++++- reflex/experimental/assets.py | 4 +++- reflex/experimental/client_state.py | 6 +++++- reflex/experimental/misc.py | 8 +++++--- reflex/reflex.py | 3 ++- reflex/state.py | 8 +++++--- reflex/testing.py | 12 ++++++++---- reflex/utils/format.py | 4 +++- 17 files changed, 88 insertions(+), 36 deletions(-) diff --git a/reflex/app.py b/reflex/app.py index 63334997c5..111dd9dfda 100644 --- a/reflex/app.py +++ b/reflex/app.py @@ -482,9 +482,8 @@ def add_page( """ # If the route is not set, get it from the callable. if route is None: - assert isinstance( - component, Callable - ), "Route must be set if component is not a callable." + if not isinstance(component, Callable): + raise ValueError("Route must be set if component is not a callable.") # Format the route. route = format.format_route(component.__name__) else: @@ -1528,6 +1527,9 @@ async def emit_update(self, update: StateUpdate, sid: str) -> None: async def on_event(self, sid, data): """Event for receiving front-end websocket events. + Raises: + RuntimeError: If the Socket.IO is badly initialized. + Args: sid: The Socket.IO session id. data: The event data. @@ -1540,9 +1542,11 @@ async def on_event(self, sid, data): self.sid_to_token[sid] = event.token # Get the event environment. - assert self.app.sio is not None + if self.app.sio is None: + raise RuntimeError("Socket.IO is not initialized.") environ = self.app.sio.get_environ(sid, self.namespace) - assert environ is not None + if environ is None: + raise RuntimeError("Socket.IO environ is not initialized.") # Get the client headers. headers = { diff --git a/reflex/compiler/utils.py b/reflex/compiler/utils.py index 443e1984fc..b105525542 100644 --- a/reflex/compiler/utils.py +++ b/reflex/compiler/utils.py @@ -44,6 +44,9 @@ def compile_import_statement(fields: list[ImportVar]) -> tuple[str, list[str]]: Args: fields: The set of fields to import from the library. + Raises: + ValueError: If there is more than one default import. + Returns: The libraries for default and rest. default: default library. When install "import def from library". @@ -54,7 +57,8 @@ def compile_import_statement(fields: list[ImportVar]) -> tuple[str, list[str]]: # Check for default imports. defaults = {field for field in fields_set if field.is_default} - assert len(defaults) < 2 + if len(defaults) >= 2: + raise ValueError("Only one default import is allowed.") # Get the default import, and the specific imports. default = next(iter({field.name for field in defaults}), "") @@ -92,6 +96,9 @@ def compile_imports(import_dict: ParsedImportDict) -> list[dict]: Args: import_dict: The import dict to compile. + Raises: + ValueError: If an import in the dict is invalid. + Returns: The list of import dict. """ @@ -106,8 +113,10 @@ def compile_imports(import_dict: ParsedImportDict) -> list[dict]: continue if not lib: - assert not default, "No default field allowed for empty library." - assert rest is not None and len(rest) > 0, "No fields to import." + if default: + raise ValueError("No default field allowed for empty library.") + if rest is None or len(rest) == 0: + raise ValueError("No fields to import.") for module in sorted(rest): import_dicts.append(get_import_dict(module)) continue diff --git a/reflex/components/base/meta.py b/reflex/components/base/meta.py index 55cb42f0ab..526233c8b3 100644 --- a/reflex/components/base/meta.py +++ b/reflex/components/base/meta.py @@ -16,13 +16,15 @@ class Title(Component): def render(self) -> dict: """Render the title component. + Raises: + ValueError: If the title is not a single string. + Returns: The rendered title component. """ # Make sure the title is a single string. - assert len(self.children) == 1 and isinstance( - self.children[0], Bare - ), "Title must be a single string." + if len(self.children) != 1 or not isinstance(self.children[0], Bare): + raise ValueError("Title must be a single string.") return super().render() diff --git a/reflex/components/component.py b/reflex/components/component.py index 7ee9b0d3a5..9bdd12f0ed 100644 --- a/reflex/components/component.py +++ b/reflex/components/component.py @@ -1744,10 +1744,14 @@ def _get_all_custom_components( Args: seen: The tags of the components that have already been seen. + Raises: + ValueError: If the tag is not set. + Returns: The set of custom components. """ - assert self.tag is not None, "The tag must be set." + if self.tag is None: + raise ValueError("The tag must be set.") # Store the seen components in a set to avoid infinite recursion. if seen is None: diff --git a/reflex/components/core/cond.py b/reflex/components/core/cond.py index d1f53be23b..1590875d3f 100644 --- a/reflex/components/core/cond.py +++ b/reflex/components/core/cond.py @@ -138,13 +138,13 @@ def cond(condition: Any, c1: Any, c2: Any = None) -> Component | Var: """ # Convert the condition to a Var. cond_var = LiteralVar.create(condition) - assert cond_var is not None, "The condition must be set." + if cond_var is None: + raise ValueError("The condition must be set.") # If the first component is a component, create a Cond component. if isinstance(c1, BaseComponent): - assert c2 is None or isinstance( - c2, BaseComponent - ), "Both arguments must be components." + if c2 is not None and not isinstance(c2, BaseComponent): + raise ValueError("Both arguments must be components.") return Cond.create(cond_var, c1, c2) # Otherwise, create a conditional Var. diff --git a/reflex/components/gridjs/datatable.py b/reflex/components/gridjs/datatable.py index aaccda9d2c..34ca626058 100644 --- a/reflex/components/gridjs/datatable.py +++ b/reflex/components/gridjs/datatable.py @@ -124,7 +124,8 @@ def _render(self) -> Tag: if types.is_dataframe(type(self.data)): # If given a pandas df break up the data and columns data = serialize(self.data) - assert isinstance(data, dict), "Serialized dataframe should be a dict." + if not isinstance(data, dict): + raise ValueError("Serialized dataframe should be a dict.") self.columns = LiteralVar.create(data["columns"]) self.data = LiteralVar.create(data["data"]) diff --git a/reflex/components/markdown/markdown.py b/reflex/components/markdown/markdown.py index 6c288c0717..1665144fd3 100644 --- a/reflex/components/markdown/markdown.py +++ b/reflex/components/markdown/markdown.py @@ -95,12 +95,16 @@ def create(cls, *children, **props) -> Component: *children: The children of the component. **props: The properties of the component. + Raises: + ValueError: If the children are not valid. + Returns: The markdown component. """ - assert ( - len(children) == 1 and types._isinstance(children[0], Union[str, Var]) - ), "Markdown component must have exactly one child containing the markdown source." + if len(children) != 1 or not types._isinstance(children[0], Union[str, Var]): + raise ValueError( + "Markdown component must have exactly one child containing the markdown source." + ) # Update the base component map with the custom component map. component_map = {**get_base_component_map(), **props.pop("component_map", {})} diff --git a/reflex/components/markdown/markdown.pyi b/reflex/components/markdown/markdown.pyi index 611770a55e..d82756f445 100644 --- a/reflex/components/markdown/markdown.pyi +++ b/reflex/components/markdown/markdown.pyi @@ -93,6 +93,9 @@ class Markdown(Component): custom_attrs: custom attribute **props: The properties of the component. + Raises: + ValueError: If the children are not valid. + Returns: The markdown component. """ diff --git a/reflex/components/tags/iter_tag.py b/reflex/components/tags/iter_tag.py index e998fc41af..86e5a57fc8 100644 --- a/reflex/components/tags/iter_tag.py +++ b/reflex/components/tags/iter_tag.py @@ -114,6 +114,9 @@ def get_arg_var_arg(self) -> Var: def render_component(self) -> Component: """Render the component. + Raises: + ValueError: If the render function takes more than 2 arguments. + Returns: The rendered component. """ @@ -132,7 +135,8 @@ def render_component(self) -> Component: component = self.render_fn(arg) else: # If the render function takes the index as an argument. - assert len(args) == 2 + if len(args) != 2: + raise ValueError("The render function must take 2 arguments.") component = self.render_fn(arg, index) # Nested foreach components or cond must be wrapped in fragments. diff --git a/reflex/event.py b/reflex/event.py index d8f0a5f0f6..95358ace1f 100644 --- a/reflex/event.py +++ b/reflex/event.py @@ -1062,6 +1062,9 @@ def fix_events( token: The user token. router_data: The optional router data to set in the event. + Raises: + ValueError: If the event type is not what was expected. + Returns: The fixed events. """ @@ -1085,7 +1088,8 @@ def fix_events( # Otherwise, create an event from the event spec. if isinstance(e, EventHandler): e = e() - assert isinstance(e, EventSpec), f"Unexpected event type, {type(e)}." + if not isinstance(e, EventSpec): + raise ValueError(f"Unexpected event type, {type(e)}.") name = format.format_event_handler(e.handler) payload = {k._js_expr: v._decode() for k, v in e.args} # type: ignore diff --git a/reflex/experimental/assets.py b/reflex/experimental/assets.py index c18ac1e84b..dcf386d8d1 100644 --- a/reflex/experimental/assets.py +++ b/reflex/experimental/assets.py @@ -24,6 +24,7 @@ def asset(relative_filename: str, subfolder: Optional[str] = None) -> str: Raises: FileNotFoundError: If the file does not exist. + ValueError: If the module is None. Returns: The relative URL to the copied asset. @@ -31,7 +32,8 @@ def asset(relative_filename: str, subfolder: Optional[str] = None) -> str: # Determine the file by which the asset is exposed. calling_file = inspect.stack()[1].filename module = inspect.getmodule(inspect.stack()[1][0]) - assert module is not None + if module is None: + raise ValueError("Module is None") caller_module_path = module.__name__.replace(".", "/") subfolder = f"{caller_module_path}/{subfolder}" if subfolder else caller_module_path diff --git a/reflex/experimental/client_state.py b/reflex/experimental/client_state.py index 438ca0a23a..c7b2260a1b 100644 --- a/reflex/experimental/client_state.py +++ b/reflex/experimental/client_state.py @@ -91,12 +91,16 @@ def create( default: The default value of the variable. global_ref: Whether the state should be accessible in any Component and on the backend. + Raises: + ValueError: If the var_name is not a string. + Returns: ClientStateVar """ if var_name is None: var_name = get_unique_variable_name() - assert isinstance(var_name, str), "var_name must be a string." + if not isinstance(var_name, str): + raise ValueError("var_name must be a string.") if default is NoValue: default_var = Var(_js_expr="") elif not isinstance(default, Var): diff --git a/reflex/experimental/misc.py b/reflex/experimental/misc.py index 716d081b82..e3d2371538 100644 --- a/reflex/experimental/misc.py +++ b/reflex/experimental/misc.py @@ -12,10 +12,12 @@ async def run_in_thread(func) -> Any: Args: func (callable): The non-async function to run. + Raises: + ValueError: If the function is an async function. + Returns: Any: The return value of the function. """ - assert not asyncio.coroutines.iscoroutinefunction( - func - ), "func must be a non-async function" + if asyncio.coroutines.iscoroutinefunction(func): + raise ValueError("func must be a non-async function") return await asyncio.get_event_loop().run_in_executor(None, func) diff --git a/reflex/reflex.py b/reflex/reflex.py index 44c0d40ff4..43ebe2eb40 100644 --- a/reflex/reflex.py +++ b/reflex/reflex.py @@ -230,7 +230,8 @@ def _run( exec.run_frontend_prod, exec.run_backend_prod, ) - assert setup_frontend and frontend_cmd and backend_cmd, "Invalid env" + if not setup_frontend or not frontend_cmd or not backend_cmd: + raise ValueError("Invalid env") # Post a telemetry event. telemetry.send(f"run-{env.value}") diff --git a/reflex/state.py b/reflex/state.py index 6af70db14f..78e2449c45 100644 --- a/reflex/state.py +++ b/reflex/state.py @@ -838,6 +838,9 @@ def get_skip_vars(cls) -> set[str]: def get_parent_state(cls) -> Type[BaseState] | None: """Get the parent state. + Raises: + ValueError: If more than one parent state is found. + Returns: The parent state. """ @@ -846,9 +849,8 @@ def get_parent_state(cls) -> Type[BaseState] | None: for base in cls.__bases__ if issubclass(base, BaseState) and base is not BaseState and not base._mixin ] - assert ( - len(parent_states) < 2 - ), f"Only one parent state is allowed {parent_states}." + if len(parent_states) >= 2: + raise ValueError(f"Only one parent state is allowed {parent_states}.") return parent_states[0] if len(parent_states) == 1 else None # type: ignore @classmethod diff --git a/reflex/testing.py b/reflex/testing.py index 503db6c2fa..db9624cf3d 100644 --- a/reflex/testing.py +++ b/reflex/testing.py @@ -340,6 +340,9 @@ async def _reset_backend_state_manager(self): This is necessary when the backend is restarted and the state manager is a StateManagerRedis instance. + + Raises: + RuntimeError: when the state manager cannot be reset """ if ( self.app_instance is not None @@ -354,7 +357,8 @@ async def _reset_backend_state_manager(self): self.app_instance._state_manager = StateManagerRedis.create( state=self.app_instance.state, ) - assert isinstance(self.app_instance.state_manager, StateManagerRedis) + if not isinstance(self.app_instance.state_manager, StateManagerRedis): + raise RuntimeError("Failed to reset state manager.") def _start_frontend(self): # Set up the frontend. @@ -787,13 +791,13 @@ def poll_for_clients(self, timeout: TimeoutType = None) -> dict[str, BaseState]: Raises: RuntimeError: when the app hasn't started running TimeoutError: when the timeout expires before any states are seen + ValueError: when the state_manager is not a memory state manager """ if self.app_instance is None: raise RuntimeError("App is not running.") state_manager = self.app_instance.state_manager - assert isinstance( - state_manager, (StateManagerMemory, StateManagerDisk) - ), "Only works with memory state manager" + if not isinstance(state_manager, (StateManagerMemory, StateManagerDisk)): + raise ValueError("Only works with memory state manager") if not self._poll_for( target=lambda: state_manager.states, timeout=timeout, diff --git a/reflex/utils/format.py b/reflex/utils/format.py index ae985a8719..4029bd275f 100644 --- a/reflex/utils/format.py +++ b/reflex/utils/format.py @@ -345,6 +345,7 @@ def format_prop( Raises: exceptions.InvalidStylePropError: If the style prop value is not a valid type. TypeError: If the prop is not valid. + ValueError: If the prop is not a string. """ # import here to avoid circular import. from reflex.event import EventChain @@ -391,7 +392,8 @@ def format_prop( raise TypeError(f"Could not format prop: {prop} of type {type(prop)}") from e # Wrap the variable in braces. - assert isinstance(prop, str), "The prop must be a string." + if not isinstance(prop, str): + raise ValueError(f"Invalid prop: {prop}. Expected a string.") return wrap(prop, "{", check_first=False)