From 2ee8c73d5a9a7a2b8ff514b4c7eb6debacb546cb Mon Sep 17 00:00:00 2001 From: Nikhil Rao Date: Sat, 11 Mar 2023 21:11:59 -0800 Subject: [PATCH] Add error message for invalid var ops (#664) --- pynecone/.templates/web/pynecone.json | 2 +- pynecone/app.py | 23 +++++---- pynecone/components/base/body.py | 4 +- pynecone/components/base/link.py | 64 ++++++------------------ pynecone/watch.py | 1 + tests/components/datadisplay/__init__.py | 1 + tests/components/datadisplay/conftest.py | 11 ++++ 7 files changed, 45 insertions(+), 61 deletions(-) diff --git a/pynecone/.templates/web/pynecone.json b/pynecone/.templates/web/pynecone.json index cf29361fa..9a46e1a4c 100644 --- a/pynecone/.templates/web/pynecone.json +++ b/pynecone/.templates/web/pynecone.json @@ -1,3 +1,3 @@ { - "version": "0.1.19" + "version": "0.1.20" } diff --git a/pynecone/app.py b/pynecone/app.py index 72bbe98a6..e2ef5cda8 100644 --- a/pynecone/app.py +++ b/pynecone/app.py @@ -204,7 +204,6 @@ class App(Base): description: str = constants.DEFAULT_DESCRIPTION, image=constants.DEFAULT_IMAGE, on_load: Optional[Union[EventHandler, List[EventHandler]]] = None, - path: Optional[str] = None, meta: List[Dict] = constants.DEFAULT_META_LIST, script_tags: Optional[List[Component]] = None, ): @@ -215,7 +214,6 @@ class App(Base): Args: component: The component to display at the page. - path: (deprecated) The path to the component. route: The route to display the component at. title: The title of the page. description: The description of the page. @@ -223,13 +221,10 @@ class App(Base): on_load: The event handler(s) that will be called each time the page load. meta: The metadata of the page. script_tags: List of script tags to be added to component - """ - if path is not None: - utils.deprecate( - "The `path` argument is deprecated for `add_page`. Use `route` instead." - ) - route = path + Raises: + TypeError: If an invalid var operation is used. + """ # If the route is not set, get it from the callable. if route is None: assert isinstance( @@ -244,7 +239,17 @@ class App(Base): self.state.setup_dynamic_args(utils.get_route_args(route)) # Generate the component if it is a callable. - component = component if isinstance(component, Component) else component() + try: + component = component if isinstance(component, Component) else component() + except TypeError as e: + message = str(e) + if "BaseVar" in message or "ComputedVar" in message: + raise TypeError( + "You may be trying to use an invalid Python function on a state var. " + "When referencing a var inside your render code, only limited var operations are supported. " + "See the var operation docs here: https://pynecone.io/docs/state/vars " + ) from e + raise e # Add meta information to the component. compiler_utils.add_meta( diff --git a/pynecone/components/base/body.py b/pynecone/components/base/body.py index 7626a94c4..00953cbc4 100644 --- a/pynecone/components/base/body.py +++ b/pynecone/components/base/body.py @@ -1,11 +1,9 @@ """Display the page body.""" from pynecone.components.component import Component -from pynecone.components.tags import Tag class Body(Component): """A body component.""" - def _render(self) -> Tag: - return Tag(name="body") + tag = "body" diff --git a/pynecone/components/base/link.py b/pynecone/components/base/link.py index 2cb039f30..fcfe34ac3 100644 --- a/pynecone/components/base/link.py +++ b/pynecone/components/base/link.py @@ -1,76 +1,44 @@ """Display the title of the current page.""" -from typing import Optional from pynecone.components.component import Component -from pynecone.components.tags import Tag from pynecone.var import Var class Link(Component): """A component that displays the title of the current page.""" + tag = "link" + # The href. href: Var[str] # The type of link. rel: Var[str] - def _render(self) -> Tag: - return Tag(name="link").add_props( - href=self.href, - rel=self.rel, - ) - class ScriptTag(Component): - """A component that creates a script tag with the speacified type and source. - - - Args: - type: This attribute indicates the type of script represented. - The value of this attribute will be one of the following: - - - module: This value causes the code to be treated as a JavaScript module. - - importmap: This value indicates that the body of the element - contains an import map. - - Any value: The embedded content is treated as a data block, and won't be - processed by the browser. - - blocking: This attribute explicitly indicates that certain operations - should be blocked on the fetching of the script. - - source: This attribute specifies the URI of an external script; this can be - used as an alternative to embedding a script directly within a document. - - integrity: This attribute contains inline metadata that a user agent can use - to verify that a fetched resource has been delivered free of unexpected manipulation - - crossorigin: To allow error logging for sites which use a separate domain for static media, - use this attribute. - - referrer_policy: Indicates which referrer to send when fetching the script, or resources fetched by the script - refrence: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#:~:text=Indicates%20which%20referrer%20to%20send%20when%20fetching%20the%20script%2C%20or%20resources%20fetched%20by%20the%20script%3A - - is_async: This attribute allows the elimination of parser-blocking JavaScript where the browser would have to - load and evaluate scripts before continuing to parse. defer has a similar effect in this case. - - defer: This Boolean attribute is set to indicate to a browser that the script is - meant to be executed after the document has been parsed, but before firing DOMContentLoaded. - - """ + """A script tag with the specified type and source.""" tag = "script" - type: Var[str] + # The type of script represented. + type_: Var[str] + # The URI of an external script. source: Var[str] - integrity: Optional[Var[str]] + # Metadata to verify the content of the script. + integrity: Var[str] - crossorigin: Optional[Var[str]] + # Whether to allow cross-origin requests. + crossorigin: Var[str] - referrer_policy: Optional[Var[str]] + # Indicates which referrer to send when fetching the script. + referrer_policy: Var[str] - is_async: Optional[Var[bool]] + # Whether to asynchronously load the script. + is_async: Var[bool] - defer: Optional[Var[bool]] + # Whether to defer loading the script. + defer: Var[bool] diff --git a/pynecone/watch.py b/pynecone/watch.py index 783ea299f..d3d38bdd1 100644 --- a/pynecone/watch.py +++ b/pynecone/watch.py @@ -44,6 +44,7 @@ class AssetFolderHandler(FileSystemEventHandler): def on_modified(self, event: FileSystemEvent): """Event handler when a file or folder was modified. + This is called every time after a file is created, modified and deleted. Args: diff --git a/tests/components/datadisplay/__init__.py b/tests/components/datadisplay/__init__.py index e69de29bb..d47573d3e 100644 --- a/tests/components/datadisplay/__init__.py +++ b/tests/components/datadisplay/__init__.py @@ -0,0 +1 @@ +"""Datadisplay component tests.""" diff --git a/tests/components/datadisplay/conftest.py b/tests/components/datadisplay/conftest.py index ca5d1b9af..903572e9a 100644 --- a/tests/components/datadisplay/conftest.py +++ b/tests/components/datadisplay/conftest.py @@ -1,3 +1,5 @@ +"""Data display component tests fixtures.""" + import pytest import pynecone as pc @@ -5,6 +7,15 @@ import pynecone as pc @pytest.fixture def data_table_state(request): + """Get a data table state. + + Args: + request: The request. + + Returns: + The data table state class. + """ + class DataTableState(pc.State): data = request.param["data"] columns = ["column1", "column2"]