Add is_dataframe check.
This commit is contained in:
parent
2008417bd7
commit
03d0aca366
2
.gitignore
vendored
2
.gitignore
vendored
@ -7,4 +7,4 @@
|
||||
bun.lockb
|
||||
poetry.lock
|
||||
dist/*
|
||||
pynetree/
|
||||
examples/
|
||||
|
@ -196,7 +196,7 @@ class App(Base):
|
||||
v = BaseVar(
|
||||
name=match.groups()[0],
|
||||
type_=str,
|
||||
state="router.query",
|
||||
state=f"{constants.ROUTER}.query",
|
||||
)
|
||||
args.append(v)
|
||||
|
||||
|
@ -224,7 +224,7 @@ class Component(Base, ABC):
|
||||
|
||||
# Add component props to the tag.
|
||||
props = {attr: getattr(self, attr) for attr in self.get_props()}
|
||||
|
||||
|
||||
# Special case for props named `type_`.
|
||||
if hasattr(self, "type_"):
|
||||
props["type"] = getattr(self, "type_")
|
||||
|
@ -1,7 +1,8 @@
|
||||
"""Table components."""
|
||||
|
||||
from typing import Any, Dict, List, Union
|
||||
from typing import Any, List
|
||||
|
||||
from pynecone import utils
|
||||
from pynecone.components.component import Component
|
||||
from pynecone.components.tags import Tag
|
||||
from pynecone.var import Var
|
||||
@ -44,7 +45,7 @@ import "gridjs/dist/theme/mermaid.css";
|
||||
"""
|
||||
|
||||
def _render(self) -> Tag:
|
||||
if type(self.data).__name__ == "DataFrame":
|
||||
if utils.is_dataframe(type(self.data)):
|
||||
self.columns = Var.create(list(self.data.columns.values.tolist())) # type: ignore
|
||||
self.data = Var.create(list(self.data.values.tolist())) # type: ignore
|
||||
|
||||
|
@ -94,6 +94,8 @@ CONFIG_MODULE = "pcconfig"
|
||||
CONFIG_FILE = f"{CONFIG_MODULE}.{PY_EXT}"
|
||||
# The deployment URL.
|
||||
PRODUCTION_BACKEND_URL = "https://{username}-{app_name}.api.pynecone.app"
|
||||
# Token expiration time in seconds.
|
||||
TOKEN_EXPIRATION = 60 * 60
|
||||
|
||||
|
||||
# Env modes
|
||||
|
@ -8,7 +8,7 @@ import traceback
|
||||
from abc import ABC
|
||||
from typing import Any, Callable, ClassVar, Dict, List, Optional, Sequence, Set, Type
|
||||
|
||||
from pynecone import utils
|
||||
from pynecone import constants, utils
|
||||
from pynecone.base import Base
|
||||
from pynecone.event import Event, EventHandler, EventSpec, window_alert
|
||||
from pynecone.var import BaseVar, ComputedVar, Var
|
||||
@ -320,35 +320,6 @@ class State(Base, ABC):
|
||||
Returns:
|
||||
The state update after processing the event.
|
||||
"""
|
||||
|
||||
def fix_events(events):
|
||||
if events is None:
|
||||
return []
|
||||
if not isinstance(events, List):
|
||||
events = [events]
|
||||
out = []
|
||||
for e in events:
|
||||
if isinstance(e, Event):
|
||||
out.append(
|
||||
Event(
|
||||
token=event.token,
|
||||
name=e.name,
|
||||
payload=e.payload,
|
||||
)
|
||||
)
|
||||
else:
|
||||
if isinstance(e, EventHandler):
|
||||
e = e()
|
||||
assert isinstance(e, EventSpec)
|
||||
out.append(
|
||||
Event(
|
||||
token=event.token,
|
||||
name=utils.to_snake_case(e.handler.fn.__qualname__),
|
||||
payload=dict(e.args),
|
||||
)
|
||||
)
|
||||
return out
|
||||
|
||||
# Get the event handler.
|
||||
path = event.name.split(".")
|
||||
path, name = path[:-1], path[-1]
|
||||
@ -367,10 +338,16 @@ class State(Base, ABC):
|
||||
print(error)
|
||||
return StateUpdate(events=[window_alert(error)])
|
||||
|
||||
# Return the substate and the delta.
|
||||
events = fix_events(events)
|
||||
# Fix the returned events.
|
||||
events = utils.fix_events(events, event.token)
|
||||
|
||||
# Get the delta after processing the event.
|
||||
delta = self.get_delta()
|
||||
|
||||
# Reset the dirty vars.
|
||||
self.clean()
|
||||
|
||||
# Return the state update.
|
||||
return StateUpdate(delta=delta, events=events)
|
||||
|
||||
def get_delta(self) -> Delta:
|
||||
@ -379,15 +356,21 @@ class State(Base, ABC):
|
||||
Returns:
|
||||
The delta for the state.
|
||||
"""
|
||||
# Return the dirty vars, as well as all computed vars.
|
||||
delta = {
|
||||
self.get_full_name(): {
|
||||
prop: getattr(self, prop)
|
||||
for prop in self.dirty_vars | set(self.computed_vars.keys())
|
||||
}
|
||||
}
|
||||
# Recursively find the substate deltas.
|
||||
for substate in self.dirty_substates:
|
||||
delta.update(self.substates[substate].get_delta())
|
||||
|
||||
# Format the delta.
|
||||
delta = utils.format_state(delta)
|
||||
|
||||
# Return the delta.
|
||||
return delta
|
||||
|
||||
def mark_dirty(self):
|
||||
@ -398,8 +381,11 @@ class State(Base, ABC):
|
||||
|
||||
def clean(self):
|
||||
"""Reset the dirty vars."""
|
||||
# Recursively clean the substates.
|
||||
for substate in self.dirty_substates:
|
||||
self.substates[substate].clean()
|
||||
|
||||
# Clean this state.
|
||||
self.dirty_vars = set()
|
||||
self.dirty_substates = set()
|
||||
|
||||
@ -463,7 +449,7 @@ class StateManager(Base):
|
||||
states: Dict[str, State] = {}
|
||||
|
||||
# The token expiration time (s).
|
||||
token_expiration: int = 60 * 60
|
||||
token_expiration: int = constants.TOKEN_EXPIRATION
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
"""Initialize the state manager.
|
||||
|
@ -36,7 +36,7 @@ from pynecone import constants
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from pynecone.components.component import ImportDict
|
||||
from pynecone.event import EventHandler, EventSpec
|
||||
from pynecone.event import Event, EventHandler, EventSpec
|
||||
from pynecone.var import Var
|
||||
|
||||
|
||||
@ -621,6 +621,18 @@ def get_default_app_name() -> str:
|
||||
return os.getcwd().split(os.path.sep)[-1].replace("-", "_")
|
||||
|
||||
|
||||
def is_dataframe(value: Type) -> bool:
|
||||
"""Check if the given value is a dataframe.
|
||||
|
||||
Args:
|
||||
value: The value to check.
|
||||
|
||||
Returns:
|
||||
Whether the value is a dataframe.
|
||||
"""
|
||||
return value.__name__ == "DataFrame"
|
||||
|
||||
|
||||
def format_state(value: Dict) -> Dict:
|
||||
"""Recursively format values in the given state.
|
||||
|
||||
@ -632,9 +644,8 @@ def format_state(value: Dict) -> Dict:
|
||||
"""
|
||||
if isinstance(value, go.Figure):
|
||||
return json.loads(to_json(value))["data"]
|
||||
import pandas as pd
|
||||
|
||||
if isinstance(value, pd.DataFrame):
|
||||
if is_dataframe(type(value)):
|
||||
return {
|
||||
"columns": value.columns.tolist(),
|
||||
"data": value.values.tolist(),
|
||||
@ -657,6 +668,26 @@ def get_event(state, event):
|
||||
return f"{state.get_name()}.{event}"
|
||||
|
||||
|
||||
def format_string(string: str) -> str:
|
||||
"""Format the given string as a JS string literal..
|
||||
|
||||
Args:
|
||||
string: The string to format.
|
||||
|
||||
Returns:
|
||||
The formatted string.
|
||||
"""
|
||||
# Escale backticks.
|
||||
string = string.replace("\`", "`") # type: ignore
|
||||
string = string.replace("`", "\`") # type: ignore
|
||||
|
||||
# Wrap the string so it looks like {`string`}.
|
||||
string = wrap(string, "`")
|
||||
string = wrap(string, "{")
|
||||
|
||||
return string
|
||||
|
||||
|
||||
def call_event_handler(event_handler: EventHandler, arg: Var) -> EventSpec:
|
||||
"""Call an event handler to get the event spec.
|
||||
|
||||
@ -723,6 +754,53 @@ def get_handler_args(event_spec: EventSpec, arg: Var) -> Tuple[Tuple[str, str],
|
||||
return ((args[1], arg.name),)
|
||||
|
||||
|
||||
def fix_events(events: Optional[List[Event]], token: str) -> List[Event]:
|
||||
"""Fix a list of events returned by an event handler.
|
||||
|
||||
Args:
|
||||
events: The events to fix.
|
||||
token: The user token.
|
||||
|
||||
Returns:
|
||||
The fixed events.
|
||||
"""
|
||||
# If the event handler returns nothing, return an empty list.
|
||||
if events is None:
|
||||
return []
|
||||
|
||||
# If the handler returns a single event, wrap it in a list.
|
||||
if not isinstance(events, List):
|
||||
events = [events]
|
||||
|
||||
# Fix the events created by the handler.
|
||||
out = []
|
||||
for e in events:
|
||||
|
||||
# If it is already an event, don't modify it.
|
||||
if isinstance(e, Event):
|
||||
name = e.name
|
||||
payload = e.payload
|
||||
|
||||
# Otherwise, create an event from the event spec.
|
||||
else:
|
||||
if isinstance(e, EventHandler):
|
||||
e = e()
|
||||
assert isinstance(e, EventSpec), f"Unexpected event type, {type(e)}."
|
||||
name = to_snake_case(e.handler.fn.__qualname__)
|
||||
payload = dict(e.args)
|
||||
|
||||
# Create an event and append it to the list.
|
||||
out.append(
|
||||
Event(
|
||||
token=token,
|
||||
name=name,
|
||||
payload=payload,
|
||||
)
|
||||
)
|
||||
|
||||
return out
|
||||
|
||||
|
||||
def merge_imports(*imports) -> ImportDict:
|
||||
"""Merge two import dicts together.
|
||||
|
||||
|
@ -123,10 +123,7 @@ class Var(ABC):
|
||||
else:
|
||||
out = utils.wrap(self.full_name, "{")
|
||||
if self.is_string:
|
||||
out = out.replace("\`", "`") # type: ignore
|
||||
out = out.replace("`", "\`") # type: ignore
|
||||
out = utils.wrap(out, "`")
|
||||
out = utils.wrap(out, "{")
|
||||
out = utils.format_string(out)
|
||||
return out
|
||||
|
||||
def __getitem__(self, i) -> Var:
|
||||
@ -140,7 +137,6 @@ class Var(ABC):
|
||||
"""
|
||||
# The type of the indexed var.
|
||||
type_ = str
|
||||
import pandas as pd
|
||||
|
||||
# Convert any vars to local vars.
|
||||
if isinstance(i, Var):
|
||||
@ -154,7 +150,7 @@ class Var(ABC):
|
||||
type_ = utils.get_args(self.type_)[0]
|
||||
else:
|
||||
type_ = Any
|
||||
elif utils._issubclass(self.type_, Union[dict, pd.DataFrame]):
|
||||
elif utils.is_dataframe(self.type_):
|
||||
if isinstance(i, str):
|
||||
i = utils.wrap(i, '"')
|
||||
if isinstance(self.type_, _GenericAlias):
|
||||
|
Loading…
Reference in New Issue
Block a user