General code cleanup (#312)

This commit is contained in:
Atharva Shah 2023-01-23 00:28:07 +05:30 committed by GitHub
parent 8068d5f176
commit 2ccbfff223
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 112 additions and 148 deletions

View File

@ -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.

View File

@ -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})",

View File

@ -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)

View File

@ -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)

View File

@ -68,7 +68,7 @@ class RangeSlider(ChakraComponent):
Returns:
The RangeSlider component.
"""
if len(children) == 0:
if not children:
children = [
RangeSliderTrack.create(
RangeSliderFilledTrack.create(),

View File

@ -68,7 +68,7 @@ class Slider(ChakraComponent):
Returns:
The slider component.
"""
if len(children) == 0:
if not children:
children = [
SliderTrack.create(
SliderFilledTrack.create(),

View File

@ -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()

View File

@ -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")

View File

@ -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(

View File

@ -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)

View File

@ -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(),

View File

@ -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."""

View File

@ -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.

View File

@ -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(

View File

@ -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]:

View File

@ -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.

View File

@ -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}

View File

@ -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():