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.state import State
from pynecone.style import Style from pynecone.style import Style
# Imports to be included in every Pynecone app. # Imports to be included in every Pynecone app.
DEFAULT_IMPORTS: ImportDict = { DEFAULT_IMPORTS: ImportDict = {
"react": {"useEffect", "useRef", "useState"}, "react": {"useEffect", "useRef", "useState"},

View File

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

View File

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

View File

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

View File

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

View File

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