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