diff --git a/pynecone/app.py b/pynecone/app.py index 3979d246f..b7729ca6b 100644 --- a/pynecone/app.py +++ b/pynecone/app.py @@ -221,18 +221,20 @@ class App(Base): for route in self.pages: route = "" if route == "index" else route - if new_route.startswith(route + "/[[..."): + if new_route.startswith(f"{route}/[[..."): raise ValueError( f"You cannot define a route with the same specificity as a optional catch-all route ('{route}' and '{new_route}')" ) route_catchall = utils.catchall_in_route(route) - if route_catchall and newroute_catchall: - # both route have a catchall, check if preceding path is the same - if utils.catchall_prefix(route) == utils.catchall_prefix(new_route): - raise ValueError( - f"You cannot use multiple catchall for the same dynamic path ({route} !== {new_route})" - ) + if ( + route_catchall + and newroute_catchall + and utils.catchall_prefix(route) == utils.catchall_prefix(new_route) + ): + raise ValueError( + f"You cannot use multiple catchall for the same dynamic path ({route} !== {new_route})" + ) def add_custom_404_page(self, component, title=None, image=None, description=None): """Define a custom 404 page for any url having no match. diff --git a/pynecone/compiler/templates.py b/pynecone/compiler/templates.py index 7db2740c2..19c747b1c 100644 --- a/pynecone/compiler/templates.py +++ b/pynecone/compiler/templates.py @@ -35,8 +35,8 @@ def format_import(lib: str, default: str = "", rest: Optional[Set[str]] = None) The compiled import statement. """ # Handle the case of direct imports with no libraries. - if lib == "": - assert default == "", "No default field allowed for empty library." + if not lib: + assert not default, "No default field allowed for empty library." assert rest is not None and len(rest) > 0, "No fields to import." return join([IMPORT_LIB(lib=lib) for lib in sorted(rest)]) @@ -45,12 +45,11 @@ def format_import(lib: str, default: str = "", rest: Optional[Set[str]] = None) if len(default) == 0 and len(rest) == 0: # Handle the case of importing a library with no fields. return IMPORT_LIB(lib=lib) - else: - # Handle importing specific fields from a library. - others = f'{{{", ".join(sorted(rest))}}}' if len(rest) > 0 else "" - if len(default) > 0 and len(rest) > 0: - default += ", " - return IMPORT_FIELDS(default=default, others=others, lib=lib) + # Handle importing specific fields from a library. + others = f'{{{", ".join(sorted(rest))}}}' if len(rest) > 0 else "" + if default != "" and len(rest) > 0: + default += ", " + return IMPORT_FIELDS(default=default, others=others, lib=lib) # Code to render a NextJS Document root. @@ -163,7 +162,7 @@ USE_EFFECT = join( [ "useEffect(() => {{", " if(!isReady) {{", - f" return;", + " return;", " }}", f" if (!{SOCKET}.current) {{{{", f" connect({SOCKET}, {{state}}, {{set_state}}, {RESULT}, {SET_RESULT}, {ROUTER}, {EVENT_ENDPOINT})", diff --git a/pynecone/components/component.py b/pynecone/components/component.py index c0d3f97cc..290267fd4 100644 --- a/pynecone/components/component.py +++ b/pynecone/components/component.py @@ -92,14 +92,13 @@ class Component(Base, ABC): if key in triggers: # Event triggers are bound to event chains. field_type = EventChain - else: - # If the key is not in the fields, skip it. - if key not in props: - continue - + elif key in props: # Set the field type. field_type = fields[key].type_ + else: + continue + # Check whether the key is a component prop. if utils._issubclass(field_type, Var): try: @@ -292,9 +291,9 @@ class Component(Base, ABC): ) children = [ - Bare.create(contents=Var.create(child, is_string=True)) - if not isinstance(child, Component) - else child + child + if isinstance(child, Component) + else Bare.create(contents=Var.create(child, is_string=True)) for child in children ] return cls(children=children, **props) @@ -454,7 +453,7 @@ class CustomComponent(Component): if utils._issubclass(type_, Base): try: value = BaseVar(name=value.json(), type_=type_, is_local=True) - except: + except Exception: value = Var.create(value) else: value = Var.create(value, is_string=type(value) is str) diff --git a/pynecone/components/forms/pininput.py b/pynecone/components/forms/pininput.py index 469ed3b3a..4f3064a4b 100644 --- a/pynecone/components/forms/pininput.py +++ b/pynecone/components/forms/pininput.py @@ -77,7 +77,7 @@ class PinInput(ChakraComponent): Returns: The pin input component. """ - if len(children) == 0 and "length" in props: + if not children and "length" in props: children = [PinInputField()] * props["length"] return super().create(*children, **props) diff --git a/pynecone/components/forms/rangeslider.py b/pynecone/components/forms/rangeslider.py index f486beade..82be15d02 100644 --- a/pynecone/components/forms/rangeslider.py +++ b/pynecone/components/forms/rangeslider.py @@ -68,7 +68,7 @@ class RangeSlider(ChakraComponent): Returns: The RangeSlider component. """ - if len(children) == 0: + if not children: children = [ RangeSliderTrack.create( RangeSliderFilledTrack.create(), diff --git a/pynecone/components/forms/slider.py b/pynecone/components/forms/slider.py index ff86315c5..3d0175d49 100644 --- a/pynecone/components/forms/slider.py +++ b/pynecone/components/forms/slider.py @@ -68,7 +68,7 @@ class Slider(ChakraComponent): Returns: The slider component. """ - if len(children) == 0: + if not children: children = [ SliderTrack.create( SliderFilledTrack.create(), diff --git a/pynecone/components/graphing/plotly.py b/pynecone/components/graphing/plotly.py index ab16c4a3c..2423777aa 100644 --- a/pynecone/components/graphing/plotly.py +++ b/pynecone/components/graphing/plotly.py @@ -42,11 +42,13 @@ const Plot = dynamic(() => import('react-plotly.js'), { ssr: false }); """ def _render(self) -> Tag: - if isinstance(self.data, Figure): - if self.layout is None: - if self.width is not None: - layout = Var.create({"width": self.width, "height": self.height}) - assert layout is not None - self.layout = layout + if ( + isinstance(self.data, Figure) + and self.layout is None + and self.width is not None + ): + layout = Var.create({"width": self.width, "height": self.height}) + assert layout is not None + self.layout = layout return super()._render() diff --git a/pynecone/components/graphing/victory.py b/pynecone/components/graphing/victory.py index 2db2b48f7..2ccfd3d88 100644 --- a/pynecone/components/graphing/victory.py +++ b/pynecone/components/graphing/victory.py @@ -78,10 +78,9 @@ def format_area(x: List, y: List, y0: Optional[List] = None) -> List: """ if y0 is None: return format_xy(x, y) - else: - if len(x) != len(y) or len(x) != len(y0): - raise ValueError("x, y, and y0 must be the same length") - return [{"x": x[i], "y": y[i], "y0": y0[i]} for i in range(len(x))] + if len(x) != len(y) or len(x) != len(y0): + raise ValueError("x, y, and y0 must be the same length") + return [{"x": x[i], "y": y[i], "y0": y0[i]} for i in range(len(x))] def format_bar(x: List, y: List, y0: Optional[List] = None) -> List: @@ -100,10 +99,9 @@ def format_bar(x: List, y: List, y0: Optional[List] = None) -> List: """ if y0 is None: return format_xy(x, y) - else: - if len(x) != len(y) or len(x) != len(y0): - raise ValueError("x, y, and y0 must be the same length") - return [{"x": x[i], "y": y[i], "y0": y0[i]} for i in range(len(x))] + if len(x) != len(y) or len(x) != len(y0): + raise ValueError("x, y, and y0 must be the same length") + return [{"x": x[i], "y": y[i], "y0": y0[i]} for i in range(len(x))] def format_box_plot( @@ -135,40 +133,37 @@ def format_box_plot( ValueError: If y is not provided and min, max, median, q1, and q3 are not provided. ValueError: If y is not provided and x, min, max, median, q1, and q3 are not the same length. """ - data = [] if x is None: raise ValueError("x must be specified") if y is not None: return format_xy(x, y) - else: - if min_ is None or max_ is None or median is None or q1 is None or q3 is None: - raise ValueError( - "min, max, median, q1, and q3 must be specified if y is not provided" - ) - if ( - len(x) != len(min_) - or len(x) != len(max_) - or len(x) != len(median) - or len(x) != len(q1) - or len(x) != len(q3) - ): - raise ValueError( - "x, min, max, median, q1, and q3 must be the same length and specified if y is not provided" - ) - for i in range(len(x)): - data.append( - { - "x": x[i], - "min": min_[i], - "max": max_[i], - "median": median[i], - "q1": q1[i], - "q3": q3[i], - } - ) - return data + if min_ is None or max_ is None or median is None or q1 is None or q3 is None: + raise ValueError( + "min, max, median, q1, and q3 must be specified if y is not provided" + ) + if ( + len(x) != len(min_) + or len(x) != len(max_) + or len(x) != len(median) + or len(x) != len(q1) + or len(x) != len(q3) + ): + raise ValueError( + "x, min, max, median, q1, and q3 must be the same length and specified if y is not provided" + ) + return [ + { + "x": x[i], + "min": min_[i], + "max": max_[i], + "median": median[i], + "q1": q1[i], + "q3": q3[i], + } + for i in range(len(x)) + ] def format_histogram(x: List) -> List: @@ -210,10 +205,9 @@ def format_pie(x: List, y: List, label: Optional[List] = None) -> List: if label is None: return format_xy(x, y) - else: - if len(x) != len(y) or len(x) != len(label): - raise ValueError("x, y, and label must be the same length") - return [{"x": x[i], "y": y[i], "label": label[i]} for i in range(len(x))] + if len(x) != len(y) or len(x) != len(label): + raise ValueError("x, y, and label must be the same length") + return [{"x": x[i], "y": y[i], "label": label[i]} for i in range(len(x))] def format_voronoi(x: List, y: List) -> List: @@ -314,26 +308,26 @@ def data(graph: str, x: List, y: Optional[List] = None, **kwargs) -> List: ValueError: If graph is not provided. ValueError: If graph is not supported. """ - if graph == "box_plot": - return format_box_plot(x, y, **kwargs) + if graph == "area": + return format_area(x, y, **kwargs) # type: ignore elif graph == "bar": return format_bar(x, y) # type: ignore - elif graph == "line": - return format_line(x, y) # type: ignore - elif graph == "scatter": - return format_scatter(x, y, **kwargs) # type: ignore - elif graph == "area": - return format_area(x, y, **kwargs) # type: ignore - elif graph == "histogram": - return format_histogram(x) - elif graph == "pie": - return format_pie(x, y, **kwargs) # type: ignore - elif graph == "voronoi": - return format_voronoi(x, y) # type: ignore + elif graph == "box_plot": + return format_box_plot(x, y, **kwargs) elif graph == "candlestick": return format_candlestick(x, **kwargs) elif graph == "error_bar": return format_error_bar(x, y, **kwargs) # type: ignore + elif graph == "histogram": + return format_histogram(x) + elif graph == "line": + return format_line(x, y) # type: ignore + elif graph == "pie": + return format_pie(x, y, **kwargs) # type: ignore + elif graph == "scatter": + return format_scatter(x, y, **kwargs) # type: ignore + elif graph == "voronoi": + return format_voronoi(x, y) # type: ignore else: raise ValueError("Invalid graph type") diff --git a/pynecone/components/layout/foreach.py b/pynecone/components/layout/foreach.py index a828dadf8..0920ed202 100644 --- a/pynecone/components/layout/foreach.py +++ b/pynecone/components/layout/foreach.py @@ -31,7 +31,7 @@ class Foreach(Component): """ try: type_ = iterable.type_.__args__[0] - except: + except Exception: type_ = Any arg = BaseVar(name="_", type_=type_, is_local=True) return cls( diff --git a/pynecone/components/navigation/link.py b/pynecone/components/navigation/link.py index 606f1a6f5..74b3ed205 100644 --- a/pynecone/components/navigation/link.py +++ b/pynecone/components/navigation/link.py @@ -34,9 +34,5 @@ class Link(ChakraComponent): Returns: The component. """ - kwargs = {} - if "href" in props: - kwargs["href"] = props.pop("href") - else: - kwargs["href"] = "#" + kwargs = {"href": props.pop("href") if "href" in props else "#"} return NextLink.create(super().create(*children, **props), **kwargs) diff --git a/pynecone/components/tags/iter_tag.py b/pynecone/components/tags/iter_tag.py index 92769733b..a588eef54 100644 --- a/pynecone/components/tags/iter_tag.py +++ b/pynecone/components/tags/iter_tag.py @@ -91,7 +91,7 @@ class IterTag(Tag): """ try: type_ = self.iterable.type_.__args__[0] - except: + except Exception: type_ = Any arg = BaseVar( name=utils.get_unique_variable_name(), diff --git a/pynecone/constants.py b/pynecone/constants.py index 3063a8dc2..5d8cc7e22 100644 --- a/pynecone/constants.py +++ b/pynecone/constants.py @@ -195,11 +195,11 @@ class Endpoint(Enum): class PathArgType(SimpleNamespace): """Type of pathArg extracted from URI path.""" + # Typecast to str is needed for Enum to work. SINGLE = str("arg_single") LIST = str("arg_list") -# ROUTE REGEXs class RouteRegex(SimpleNamespace): """Regex used for extracting path args in path.""" diff --git a/pynecone/event.py b/pynecone/event.py index 73fa08562..a2f77d901 100644 --- a/pynecone/event.py +++ b/pynecone/event.py @@ -65,10 +65,10 @@ class EventHandler(Base): # Otherwise, convert to JSON. try: values.append(json.dumps(arg)) - except TypeError: + except TypeError as e: raise TypeError( f"Arguments to event handlers must be Vars or JSON-serializable. Got {arg} of type {type(arg)}." - ) + ) from e payload = tuple(zip(fn_args, values)) # Return the event spec. diff --git a/pynecone/state.py b/pynecone/state.py index 9ee2cbf7f..d98d035cf 100644 --- a/pynecone/state.py +++ b/pynecone/state.py @@ -157,7 +157,7 @@ class State(Base, ABC): Returns: The substates of the state. """ - return {subclass for subclass in cls.__subclasses__()} + return set(cls.__subclasses__()) @classmethod @functools.lru_cache() @@ -408,7 +408,7 @@ class State(Base, ABC): events = await fn(**event.payload) else: events = fn(**event.payload) - except: + except Exception: error = traceback.format_exc() print(error) return StateUpdate( diff --git a/pynecone/utils.py b/pynecone/utils.py index 113ef0a62..bc2bcb559 100644 --- a/pynecone/utils.py +++ b/pynecone/utils.py @@ -1,7 +1,9 @@ """General utility functions.""" + from __future__ import annotations +import contextlib import inspect import json import os @@ -87,14 +89,11 @@ def is_generic_alias(cls: GenericType) -> bool: if isinstance(cls, _GenericAlias): return True - try: + with contextlib.suppress(ImportError): from typing import _SpecialGenericAlias # type: ignore if isinstance(cls, _SpecialGenericAlias): return True - except ImportError: - pass - # For newer versions of Python. try: from types import GenericAlias # type: ignore @@ -113,17 +112,11 @@ def is_union(cls: GenericType) -> bool: Returns: Whether the class is a Union. """ - try: + with contextlib.suppress(ImportError): from typing import _UnionGenericAlias # type: ignore return isinstance(cls, _UnionGenericAlias) - except ImportError: - pass - - if is_generic_alias(cls): - return cls.__origin__ == Union - - return False + return cls.__origin__ == Union if is_generic_alias(cls) else False def get_base_class(cls: GenericType) -> Type: @@ -138,10 +131,7 @@ def get_base_class(cls: GenericType) -> Type: if is_union(cls): return tuple(get_base_class(arg) for arg in get_args(cls)) - if is_generic_alias(cls): - return get_base_class(cls.__origin__) - - return cls + return get_base_class(cls.__origin__) if is_generic_alias(cls) else cls def _issubclass(cls: GenericType, cls_check: GenericType) -> bool: @@ -157,7 +147,7 @@ def _issubclass(cls: GenericType, cls_check: GenericType) -> bool: # Special check for Any. if cls_check == Any: return True - if cls == Any or cls == Callable: + if cls in [Any, Callable]: return False cls_base = get_base_class(cls) cls_check_base = get_base_class(cls_check) @@ -361,8 +351,7 @@ def get_app() -> ModuleType: config = get_config() module = ".".join([config.app_name, config.app_name]) sys.path.insert(0, os.getcwd()) - app = __import__(module, fromlist=(constants.APP_VAR,)) - return app + return __import__(module, fromlist=(constants.APP_VAR,)) def create_config(app_name: str): @@ -570,12 +559,7 @@ def get_num_workers() -> int: Returns: The number of backend worker processes. """ - if get_redis() is None: - # If there is no redis, then just use 1 worker. - return 1 - - # Use the number of cores * 2 + 1. - return (os.cpu_count() or 1) * 2 + 1 + return 1 if get_redis() is None else (os.cpu_count() or 1) * 2 + 1 def get_api_port() -> int: @@ -888,9 +872,7 @@ def format_route(route: str) -> str: """ route = route.strip(os.path.sep) route = to_snake_case(route).replace("_", "-") - if route == "": - return constants.INDEX_ROUTE - return route + return constants.INDEX_ROUTE if route == "" else route def format_cond( @@ -936,7 +918,7 @@ def format_event_handler(handler: EventHandler) -> str: try: # Try to get the state from the module. state = vars(sys.modules[handler.fn.__module__])[state_name] - except: + except Exception: # If the state isn't in the module, just return the function name. return handler.fn.__qualname__ return ".".join([state.get_full_name(), name]) @@ -1128,10 +1110,7 @@ def get_handler_args(event_spec: EventSpec, arg: Var) -> Tuple[Tuple[str, str], The handler args. """ args = inspect.getfullargspec(event_spec.handler.fn).args - if len(args) > 2: - return event_spec.args - else: - return ((args[1], arg.name),) + return event_spec.args if len(args) > 2 else ((args[1], arg.name),) def fix_events(events: Optional[List[Event]], token: str) -> List[Event]: diff --git a/pynecone/var.py b/pynecone/var.py index d3b8e88d7..21816bd66 100644 --- a/pynecone/var.py +++ b/pynecone/var.py @@ -64,7 +64,7 @@ class Var(ABC): value = json.loads(to_json(value))["data"] type_ = Figure - name = json.dumps(value) if not isinstance(value, str) else value + name = value if isinstance(value, str) else json.dumps(value) return BaseVar(name=name, type_=type_, is_local=is_local, is_string=is_string) @@ -118,10 +118,7 @@ class Var(ABC): Returns: The wrapped var, i.e. {state.var}. """ - if self.is_local: - out = self.full_name - else: - out = utils.wrap(self.full_name, "{") + out = self.full_name if self.is_local else utils.wrap(self.full_name, "{") if self.is_string: out = utils.format_string(out) return out @@ -263,7 +260,7 @@ class Var(ABC): if other is None: name = f"{op}{self.full_name}" else: - props = (self, other) if not flip else (other, self) + props = (other, self) if flip else (self, other) name = f"{props[0].full_name} {op} {props[1].full_name}" if fn is None: name = utils.wrap(name, "(") @@ -620,9 +617,7 @@ class Var(ABC): Returns: The full name of the var. """ - if self.state == "": - return self.name - return ".".join([self.state, self.name]) + return self.name if self.state == "" else ".".join([self.state, self.name]) def set_state(self, state: Type[State]) -> Any: """Set the state of the var. @@ -685,9 +680,7 @@ class BaseVar(Var, Base): return {} if issubclass(type_, tuple): return () - if issubclass(type_, set): - return set() - return None + return set() if issubclass(type_, set) else None def get_setter_name(self, include_state: bool = True) -> str: """Get the name of the var's generated setter function. diff --git a/tests/components/test_component.py b/tests/components/test_component.py index aba4fcbff..568f1b8b0 100644 --- a/tests/components/test_component.py +++ b/tests/components/test_component.py @@ -300,4 +300,4 @@ def test_custom_component_hash(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} + assert {component1, component2} == {component1} diff --git a/tests/test_var.py b/tests/test_var.py index 74025b874..e00726713 100644 --- a/tests/test_var.py +++ b/tests/test_var.py @@ -195,9 +195,9 @@ def test_var_list_slicing(): """Test that we can slice into list vars.""" lst = BaseVar(name="lst", type_=List[int]) - assert str(lst[0:1]) == "{lst.slice(0, 1)}" assert str(lst[:1]) == "{lst.slice(0, 1)}" - assert str(lst[0:]) == "{lst.slice(0, undefined)}" + assert str(lst[:1]) == "{lst.slice(0, 1)}" + assert str(lst[:]) == "{lst.slice(0, undefined)}" def test_dict_indexing():