Add better error messages (#18)

This commit is contained in:
Nikhil Rao 2022-11-29 19:22:48 -08:00 committed by GitHub
parent f710fc1a82
commit f0355e7f39
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 49 additions and 4 deletions

View File

@ -253,10 +253,22 @@ class Component(Base, ABC):
Returns: Returns:
The component. The component.
Raises:
TypeError: If an invalid child is passed.
""" """
# Import here to avoid circular imports. # Import here to avoid circular imports.
from pynecone.components.base.bare import Bare from pynecone.components.base.bare import Bare
# Validate all the children.
for child in children:
if not utils._isinstance(child, ComponentChild):
raise TypeError(
"Children of Pynecone components must be other components, "
"state vars, or primitive Python types. "
f"Got child of type {type(child)}.",
)
children = [ children = [
Bare.create(contents=Var.create(child, is_string=True)) Bare.create(contents=Var.create(child, is_string=True))
if not isinstance(child, Component) if not isinstance(child, Component)
@ -348,3 +360,4 @@ class Component(Base, ABC):
# Map from component to styling. # Map from component to styling.
ComponentStyle = Dict[Union[str, Type[Component]], Any] ComponentStyle = Dict[Union[str, Type[Component]], Any]
ComponentChild = Union[utils.PrimitiveType, Var, Component]

View File

@ -10,7 +10,7 @@ from typing import Any, Callable, ClassVar, Dict, List, Optional, Sequence, Set,
from pynecone import constants, utils from pynecone import constants, utils
from pynecone.base import Base from pynecone.base import Base
from pynecone.event import Event, EventHandler, EventSpec, window_alert from pynecone.event import Event, EventHandler, window_alert
from pynecone.var import BaseVar, ComputedVar, Var from pynecone.var import BaseVar, ComputedVar, Var
Delta = Dict[str, Any] Delta = Dict[str, Any]
@ -70,6 +70,9 @@ class State(Base, ABC):
Args: Args:
**kwargs: The kwargs to pass to the pydantic init_subclass method. **kwargs: The kwargs to pass to the pydantic init_subclass method.
Raises:
TypeError: If the class has a var with an invalid type.
""" """
super().__init_subclass__(**kwargs) super().__init_subclass__(**kwargs)
@ -103,6 +106,13 @@ class State(Base, ABC):
# Setup the base vars at the class level. # Setup the base vars at the class level.
for prop in cls.base_vars.values(): for prop in cls.base_vars.values():
if not utils._issubclass(prop.type_, utils.StateVar):
raise TypeError(
"State vars must be primitive Python types, "
"Plotly figures, Pandas dataframes, "
"or subclasses of pc.Base. "
f'Found var "{prop.name}" with type {prop.type_}.'
)
cls._set_var(prop) cls._set_var(prop)
cls._create_setter(prop) cls._create_setter(prop)
cls._set_default_value(prop) cls._set_default_value(prop)

View File

@ -32,6 +32,8 @@ from plotly.io import to_json
from rich.console import Console from rich.console import Console
from pynecone import constants from pynecone import constants
from pynecone.base import Base
if TYPE_CHECKING: if TYPE_CHECKING:
from pynecone.components.component import ImportDict from pynecone.components.component import ImportDict
@ -49,6 +51,10 @@ console = Console()
# Union of generic types. # Union of generic types.
GenericType = Union[Type, _GenericAlias] GenericType = Union[Type, _GenericAlias]
# Valid state var types.
PrimitiveType = Union[int, float, bool, str, list, dict, tuple]
StateVar = Union[PrimitiveType, Base, None]
def get_args(alias: _GenericAlias) -> Tuple[Type, ...]: def get_args(alias: _GenericAlias) -> Tuple[Type, ...]:
"""Get the arguments of a type alias. """Get the arguments of a type alias.
@ -703,17 +709,33 @@ def format_state(value: Any) -> Dict:
Returns: Returns:
The formatted state. The formatted state.
Raises:
TypeError: If the given value is not a valid state.
""" """
if isinstance(value, go.Figure): # Convert plotly figures to JSON.
if _isinstance(value, go.Figure):
return json.loads(to_json(value))["data"] return json.loads(to_json(value))["data"]
# Convert pandas dataframes to JSON.
if is_dataframe(type(value)): if is_dataframe(type(value)):
return { return {
"columns": value.columns.tolist(), "columns": value.columns.tolist(),
"data": value.values.tolist(), "data": value.values.tolist(),
} }
if isinstance(value, dict):
# Handle dicts.
if _isinstance(value, dict):
return {k: format_state(v) for k, v in value.items()} return {k: format_state(v) for k, v in value.items()}
# Make sure the value is JSON serializable.
if not _isinstance(value, StateVar):
raise TypeError(
"State vars must be primitive Python types, "
"or subclasses of pc.Base. "
f"Got var of type {type(value)}."
)
return value return value

View File

@ -30,7 +30,7 @@ plotly = "^5.10.0"
pydantic = "1.10.2" pydantic = "1.10.2"
requests = "^2.28.1" requests = "^2.28.1"
sqlmodel = "^0.0.8" sqlmodel = "^0.0.8"
typer = "^0.7.0" typer = "0.4.2"
uvicorn = "^0.20.0" uvicorn = "^0.20.0"
rich = "^12.6.0" rich = "^12.6.0"
redis = "^4.3.5" redis = "^4.3.5"