
* enable PGH, bump pyright and fix all #type: ignore * relock poetry file * ignore incompatible override * fix varop tests * ignore missing imports * fix * fix stuff * fix tests * rechange tests * relock with poetry 2.0
377 lines
12 KiB
Python
377 lines
12 KiB
Python
"""Benchmark tests for apps with varying component numbers."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import functools
|
|
import time
|
|
from typing import Generator
|
|
|
|
import pytest
|
|
|
|
from benchmarks import WINDOWS_SKIP_REASON
|
|
from reflex import constants
|
|
from reflex.compiler import utils
|
|
from reflex.testing import AppHarness, chdir
|
|
from reflex.utils import build
|
|
from reflex.utils.prerequisites import get_web_dir
|
|
|
|
web_pages = get_web_dir() / constants.Dirs.PAGES
|
|
|
|
|
|
def render_component(num: int):
|
|
"""Generate a number of components based on num.
|
|
|
|
Args:
|
|
num: number of components to produce.
|
|
|
|
Returns:
|
|
The rendered number of components.
|
|
"""
|
|
import reflex as rx
|
|
|
|
return [
|
|
rx.fragment(
|
|
rx.box(
|
|
rx.accordion.root(
|
|
rx.accordion.item(
|
|
header="Full Ingredients",
|
|
content="Yes. It's built with accessibility in mind.",
|
|
font_size="3em",
|
|
),
|
|
rx.accordion.item(
|
|
header="Applications",
|
|
content="Yes. It's unstyled by default, giving you freedom over the look and feel.",
|
|
),
|
|
collapsible=True,
|
|
variant="ghost",
|
|
width="25rem",
|
|
),
|
|
padding_top="20px",
|
|
),
|
|
rx.box(
|
|
rx.drawer.root(
|
|
rx.drawer.trigger(
|
|
rx.button("Open Drawer with snap points"), as_child=True
|
|
),
|
|
rx.drawer.overlay(),
|
|
rx.drawer.portal(
|
|
rx.drawer.content(
|
|
rx.flex(
|
|
rx.drawer.title("Drawer Content"),
|
|
rx.drawer.description("Drawer description"),
|
|
rx.drawer.close(
|
|
rx.button("Close Button"),
|
|
as_child=True,
|
|
),
|
|
direction="column",
|
|
margin="5em",
|
|
align_items="center",
|
|
),
|
|
top="auto",
|
|
height="100%",
|
|
flex_direction="column",
|
|
background_color="var(--green-3)",
|
|
),
|
|
),
|
|
snap_points=["148px", "355px", 1],
|
|
),
|
|
),
|
|
rx.box(
|
|
rx.callout(
|
|
"You will need admin privileges to install and access this application.",
|
|
icon="info",
|
|
size="3",
|
|
),
|
|
),
|
|
rx.box(
|
|
rx.table.root(
|
|
rx.table.header(
|
|
rx.table.row(
|
|
rx.table.column_header_cell("Full name"),
|
|
rx.table.column_header_cell("Email"),
|
|
rx.table.column_header_cell("Group"),
|
|
),
|
|
),
|
|
rx.table.body(
|
|
rx.table.row(
|
|
rx.table.row_header_cell("Danilo Sousa"),
|
|
rx.table.cell("danilo@example.com"),
|
|
rx.table.cell("Developer"),
|
|
),
|
|
rx.table.row(
|
|
rx.table.row_header_cell("Zahra Ambessa"),
|
|
rx.table.cell("zahra@example.com"),
|
|
rx.table.cell("Admin"),
|
|
),
|
|
rx.table.row(
|
|
rx.table.row_header_cell("Jasper Eriksson"),
|
|
rx.table.cell("jasper@example.com"),
|
|
rx.table.cell("Developer"),
|
|
),
|
|
),
|
|
)
|
|
),
|
|
)
|
|
] * num
|
|
|
|
|
|
def AppWithTenComponentsOnePage():
|
|
"""A reflex app with roughly 10 components on one page."""
|
|
import reflex as rx
|
|
|
|
def index() -> rx.Component:
|
|
return rx.center(rx.vstack(*render_component(1)))
|
|
|
|
app = rx.App(_state=rx.State)
|
|
app.add_page(index)
|
|
|
|
|
|
def AppWithHundredComponentOnePage():
|
|
"""A reflex app with roughly 100 components on one page."""
|
|
import reflex as rx
|
|
|
|
def index() -> rx.Component:
|
|
return rx.center(rx.vstack(*render_component(100)))
|
|
|
|
app = rx.App(_state=rx.State)
|
|
app.add_page(index)
|
|
|
|
|
|
def AppWithThousandComponentsOnePage():
|
|
"""A reflex app with roughly 1000 components on one page."""
|
|
import reflex as rx
|
|
|
|
def index() -> rx.Component:
|
|
return rx.center(rx.vstack(*render_component(1000)))
|
|
|
|
app = rx.App(_state=rx.State)
|
|
app.add_page(index)
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def app_with_10_components(
|
|
tmp_path_factory,
|
|
) -> Generator[AppHarness, None, None]:
|
|
"""Start Blank Template app at tmp_path via AppHarness.
|
|
|
|
Args:
|
|
tmp_path_factory: pytest tmp_path_factory fixture
|
|
|
|
Yields:
|
|
running AppHarness instance
|
|
"""
|
|
root = tmp_path_factory.mktemp("app10components")
|
|
|
|
yield AppHarness.create(
|
|
root=root,
|
|
app_source=functools.partial(
|
|
AppWithTenComponentsOnePage,
|
|
render_component=render_component, # pyright: ignore [reportCallIssue]
|
|
),
|
|
)
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def app_with_100_components(
|
|
tmp_path_factory,
|
|
) -> Generator[AppHarness, None, None]:
|
|
"""Start Blank Template app at tmp_path via AppHarness.
|
|
|
|
Args:
|
|
tmp_path_factory: pytest tmp_path_factory fixture
|
|
|
|
Yields:
|
|
running AppHarness instance
|
|
"""
|
|
root = tmp_path_factory.mktemp("app100components")
|
|
|
|
yield AppHarness.create(
|
|
root=root,
|
|
app_source=functools.partial(
|
|
AppWithHundredComponentOnePage,
|
|
render_component=render_component, # pyright: ignore [reportCallIssue]
|
|
),
|
|
)
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def app_with_1000_components(
|
|
tmp_path_factory,
|
|
) -> Generator[AppHarness, None, None]:
|
|
"""Create an app with 1000 components at tmp_path via AppHarness.
|
|
|
|
Args:
|
|
tmp_path_factory: pytest tmp_path_factory fixture
|
|
|
|
Yields:
|
|
an AppHarness instance
|
|
"""
|
|
root = tmp_path_factory.mktemp("app1000components")
|
|
|
|
yield AppHarness.create(
|
|
root=root,
|
|
app_source=functools.partial(
|
|
AppWithThousandComponentsOnePage,
|
|
render_component=render_component, # pyright: ignore [reportCallIssue]
|
|
),
|
|
)
|
|
|
|
|
|
@pytest.mark.skipif(constants.IS_WINDOWS, reason=WINDOWS_SKIP_REASON)
|
|
@pytest.mark.benchmark(
|
|
group="Compile time of varying component numbers",
|
|
timer=time.perf_counter,
|
|
disable_gc=True,
|
|
warmup=False,
|
|
)
|
|
def test_app_10_compile_time_cold(benchmark, app_with_10_components):
|
|
"""Test the compile time on a cold start for an app with roughly 10 components.
|
|
|
|
Args:
|
|
benchmark: The benchmark fixture.
|
|
app_with_10_components: The app harness.
|
|
"""
|
|
|
|
def setup():
|
|
with chdir(app_with_10_components.app_path):
|
|
utils.empty_dir(web_pages, ["_app.js"])
|
|
app_with_10_components._initialize_app()
|
|
build.setup_frontend(app_with_10_components.app_path)
|
|
|
|
def benchmark_fn():
|
|
with chdir(app_with_10_components.app_path):
|
|
app_with_10_components.app_instance._compile()
|
|
|
|
benchmark.pedantic(benchmark_fn, setup=setup, rounds=10)
|
|
|
|
|
|
@pytest.mark.benchmark(
|
|
group="Compile time of varying component numbers",
|
|
min_rounds=5,
|
|
timer=time.perf_counter,
|
|
disable_gc=True,
|
|
warmup=False,
|
|
)
|
|
def test_app_10_compile_time_warm(benchmark, app_with_10_components):
|
|
"""Test the compile time on a warm start for an app with roughly 10 components.
|
|
|
|
Args:
|
|
benchmark: The benchmark fixture.
|
|
app_with_10_components: The app harness.
|
|
"""
|
|
with chdir(app_with_10_components.app_path):
|
|
app_with_10_components._initialize_app()
|
|
build.setup_frontend(app_with_10_components.app_path)
|
|
|
|
def benchmark_fn():
|
|
with chdir(app_with_10_components.app_path):
|
|
app_with_10_components.app_instance._compile()
|
|
|
|
benchmark(benchmark_fn)
|
|
|
|
|
|
@pytest.mark.skipif(constants.IS_WINDOWS, reason=WINDOWS_SKIP_REASON)
|
|
@pytest.mark.benchmark(
|
|
group="Compile time of varying component numbers",
|
|
timer=time.perf_counter,
|
|
disable_gc=True,
|
|
warmup=False,
|
|
)
|
|
def test_app_100_compile_time_cold(benchmark, app_with_100_components):
|
|
"""Test the compile time on a cold start for an app with roughly 100 components.
|
|
|
|
Args:
|
|
benchmark: The benchmark fixture.
|
|
app_with_100_components: The app harness.
|
|
"""
|
|
|
|
def setup():
|
|
with chdir(app_with_100_components.app_path):
|
|
utils.empty_dir(web_pages, ["_app.js"])
|
|
app_with_100_components._initialize_app()
|
|
build.setup_frontend(app_with_100_components.app_path)
|
|
|
|
def benchmark_fn():
|
|
with chdir(app_with_100_components.app_path):
|
|
app_with_100_components.app_instance._compile()
|
|
|
|
benchmark.pedantic(benchmark_fn, setup=setup, rounds=5)
|
|
|
|
|
|
@pytest.mark.benchmark(
|
|
group="Compile time of varying component numbers",
|
|
min_rounds=5,
|
|
timer=time.perf_counter,
|
|
disable_gc=True,
|
|
warmup=False,
|
|
)
|
|
def test_app_100_compile_time_warm(benchmark, app_with_100_components):
|
|
"""Test the compile time on a warm start for an app with roughly 100 components.
|
|
|
|
Args:
|
|
benchmark: The benchmark fixture.
|
|
app_with_100_components: The app harness.
|
|
"""
|
|
with chdir(app_with_100_components.app_path):
|
|
app_with_100_components._initialize_app()
|
|
build.setup_frontend(app_with_100_components.app_path)
|
|
|
|
def benchmark_fn():
|
|
with chdir(app_with_100_components.app_path):
|
|
app_with_100_components.app_instance._compile()
|
|
|
|
benchmark(benchmark_fn)
|
|
|
|
|
|
@pytest.mark.skipif(constants.IS_WINDOWS, reason=WINDOWS_SKIP_REASON)
|
|
@pytest.mark.benchmark(
|
|
group="Compile time of varying component numbers",
|
|
timer=time.perf_counter,
|
|
disable_gc=True,
|
|
warmup=False,
|
|
)
|
|
def test_app_1000_compile_time_cold(benchmark, app_with_1000_components):
|
|
"""Test the compile time on a cold start for an app with roughly 1000 components.
|
|
|
|
Args:
|
|
benchmark: The benchmark fixture.
|
|
app_with_1000_components: The app harness.
|
|
"""
|
|
|
|
def setup():
|
|
with chdir(app_with_1000_components.app_path):
|
|
utils.empty_dir(web_pages, keep_files=["_app.js"])
|
|
app_with_1000_components._initialize_app()
|
|
build.setup_frontend(app_with_1000_components.app_path)
|
|
|
|
def benchmark_fn():
|
|
with chdir(app_with_1000_components.app_path):
|
|
app_with_1000_components.app_instance._compile()
|
|
|
|
benchmark.pedantic(benchmark_fn, setup=setup, rounds=5)
|
|
|
|
|
|
@pytest.mark.benchmark(
|
|
group="Compile time of varying component numbers",
|
|
min_rounds=5,
|
|
timer=time.perf_counter,
|
|
disable_gc=True,
|
|
warmup=False,
|
|
)
|
|
def test_app_1000_compile_time_warm(benchmark, app_with_1000_components):
|
|
"""Test the compile time on a warm start for an app with roughly 1000 components.
|
|
|
|
Args:
|
|
benchmark: The benchmark fixture.
|
|
app_with_1000_components: The app harness.
|
|
"""
|
|
with chdir(app_with_1000_components.app_path):
|
|
app_with_1000_components._initialize_app()
|
|
build.setup_frontend(app_with_1000_components.app_path)
|
|
|
|
def benchmark_fn():
|
|
with chdir(app_with_1000_components.app_path):
|
|
app_with_1000_components.app_instance._compile()
|
|
|
|
benchmark(benchmark_fn)
|