Fix component decorator bugs (#203)

This commit is contained in:
Nikhil Rao 2023-01-04 15:20:33 -08:00 committed by GitHub
parent 858008d3b1
commit 3f27ce3442
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 51 additions and 34 deletions

View File

@ -11,7 +11,6 @@ from pynecone.components.component import Component, CustomComponent, ImportDict
from pynecone.state import State
from pynecone.style import Style
# Imports to be included in every Pynecone app.
DEFAULT_IMPORTS: ImportDict = {
"react": {"useEffect", "useRef", "useState"},

View File

@ -1,11 +1,8 @@
"""Common utility functions used in the compiler."""
from __future__ import annotations
import inspect
import json
import os
from typing import TYPE_CHECKING, Any, Dict, List, Set, Type
from typing import Dict, List, Set, Tuple, Type
from pynecone import constants, utils
from pynecone.compiler import templates
@ -21,14 +18,9 @@ from pynecone.components.base import (
Script,
Title,
)
from pynecone.components.component import ImportDict
from pynecone.components.component import Component, CustomComponent, ImportDict
from pynecone.state import State
from pynecone.style import Style
from pynecone.var import BaseVar, Var
if TYPE_CHECKING:
from pynecone.components.component import Component, CustomComponent
# To re-export this function.
merge_imports = utils.merge_imports
@ -170,7 +162,7 @@ def compile_render(component: Component) -> str:
return component.render()
def compile_custom_component(component: CustomComponent) -> tuple[str, ImportDict]:
def compile_custom_component(component: CustomComponent) -> Tuple[str, ImportDict]:
"""Compile a custom component.
Args:
@ -179,20 +171,18 @@ def compile_custom_component(component: CustomComponent) -> tuple[str, ImportDic
Returns:
A tuple of the compiled component and the imports required by the component.
"""
props = [
BaseVar(
name=name,
type_=prop.type_ if utils._isinstance(prop, Var) else type(prop),
is_local=True,
)
for name, prop in component.props.items()
]
# Render the component.
render = component.get_component()
# Compile the component.
render = component.component_fn(*props)
# Get the imports.
imports = {
lib: fields
for lib, fields in render.get_imports().items()
if lib != component.library
}
# Concatenate the props.
props = ", ".join([prop.name for prop in props])
props = ", ".join([prop.name for prop in component.get_prop_vars()])
# Compile the component.
return (
@ -201,7 +191,7 @@ def compile_custom_component(component: CustomComponent) -> tuple[str, ImportDic
props=props,
render=render,
),
render.get_imports(),
imports,
)

View File

@ -18,7 +18,7 @@ from pynecone.event import (
EventSpec,
)
from pynecone.style import Style
from pynecone.var import Var
from pynecone.var import BaseVar, Var
ImportDict = Dict[str, Set[str]]
@ -440,7 +440,7 @@ class CustomComponent(Component):
if utils._issubclass(type_, EventChain):
value = self._create_event_chain(key, value)
else:
value = Var.create(value)
value = Var.create(value, is_string=type(value) is str)
self.props[utils.to_camel_case(key)] = value
def __eq__(self, other) -> bool:
@ -477,7 +477,11 @@ class CustomComponent(Component):
Returns:
The set of custom components.
"""
return {self} | super().get_custom_components()
return (
{self}
| super().get_custom_components()
| self.get_component().get_custom_components()
)
def _render(self) -> Tag:
"""Define how to render the component in React.
@ -487,6 +491,28 @@ class CustomComponent(Component):
"""
return Tag(name=self.tag).add_props(**self.props)
def get_prop_vars(self) -> List[BaseVar]:
"""Get the prop vars.
Returns:
The prop vars.
"""
return [
BaseVar(
name=name,
type_=prop.type_ if utils._isinstance(prop, Var) else type(prop),
)
for name, prop in self.props.items()
]
def get_component(self) -> Component:
"""Render the component.
Returns:
The code to render the component.
"""
return self.component_fn(*self.get_prop_vars())
def custom_component(
component_fn: Callable[..., Component]

View File

@ -13,8 +13,6 @@ import signal
import string
import subprocess
import sys
import uvicorn
from urllib.parse import urlparse
from collections import defaultdict
from subprocess import PIPE
from types import ModuleType
@ -30,9 +28,11 @@ from typing import (
Type,
Union,
)
from urllib.parse import urlparse
import plotly.graph_objects as go
import typer
import uvicorn
from plotly.io import to_json
from redis import Redis
from rich.console import Console

View File

@ -161,7 +161,9 @@ class Var(ABC):
else:
type_ = Any
else:
raise TypeError("Var does not support indexing.")
raise TypeError(
f"Var {self.name} of type {self.type_} does not support indexing."
)
return BaseVar(
name=f"{self.name}[{i}]",

View File

@ -110,7 +110,7 @@ def my_component():
A test component function.
"""
def my_component(prop1: str, prop2: int):
def my_component(prop1: Var[str], prop2: Var[int]):
return Box.create(prop1, prop2)
return my_component
@ -286,7 +286,7 @@ def test_create_custom_component(my_component):
Args:
my_component: A test custom component.
"""
component = CustomComponent(component_fn=my_component)
component = CustomComponent(component_fn=my_component, prop1="test", prop2=1)
assert component.tag == "MyComponent"
assert component.get_props() == set()
assert component.get_custom_components() == {component}
@ -298,6 +298,6 @@ def test_custom_component_hash(my_component):
Args:
my_component: A test custom component.
"""
component1 = CustomComponent(component_fn=my_component)
component2 = CustomComponent(component_fn=my_component)
component1 = CustomComponent(component_fn=my_component, prop1="test", prop2=1)
component2 = CustomComponent(component_fn=my_component, prop1="test", prop2=2)
assert set([component1, component2]) == {component1}