
* 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
580 lines
17 KiB
Python
580 lines
17 KiB
Python
"""Benchmark tests for apps with varying page 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_multiple_pages(app, num: int):
|
|
"""Add multiple pages based on num.
|
|
|
|
Args:
|
|
app: The App object.
|
|
num: number of pages to render.
|
|
|
|
"""
|
|
from typing import Tuple
|
|
|
|
from rxconfig import config # pyright: ignore [reportMissingImports]
|
|
|
|
import reflex as rx
|
|
|
|
docs_url = "https://reflex.dev/docs/getting-started/introduction/"
|
|
filename = f"{config.app_name}/{config.app_name}.py"
|
|
college = [
|
|
"Stanford University",
|
|
"Arizona",
|
|
"Arizona state",
|
|
"Baylor",
|
|
"Boston College",
|
|
"Boston University",
|
|
]
|
|
|
|
class State(rx.State):
|
|
"""The app state."""
|
|
|
|
position: str
|
|
college: str
|
|
age: Tuple[int, int] = (18, 50)
|
|
salary: Tuple[int, int] = (0, 25000000)
|
|
|
|
comp1 = rx.center(
|
|
rx.theme_panel(),
|
|
rx.vstack(
|
|
rx.heading("Welcome to Reflex!", size="9"),
|
|
rx.text("Get started by editing ", rx.code(filename)),
|
|
rx.button(
|
|
"Check out our docs!",
|
|
on_click=lambda: rx.redirect(docs_url),
|
|
size="4",
|
|
),
|
|
align="center",
|
|
spacing="7",
|
|
font_size="2em",
|
|
),
|
|
height="100vh",
|
|
)
|
|
|
|
comp2 = rx.vstack(
|
|
rx.hstack(
|
|
rx.vstack(
|
|
rx.select(
|
|
["C", "PF", "SF", "PG", "SG"],
|
|
placeholder="Select a position. (All)",
|
|
on_change=State.set_position, # pyright: ignore [reportAttributeAccessIssue]
|
|
size="3",
|
|
),
|
|
rx.select(
|
|
college,
|
|
placeholder="Select a college. (All)",
|
|
on_change=State.set_college, # pyright: ignore [reportAttributeAccessIssue]
|
|
size="3",
|
|
),
|
|
),
|
|
rx.vstack(
|
|
rx.vstack(
|
|
rx.hstack(
|
|
rx.badge("Min Age: ", State.age[0]),
|
|
rx.divider(orientation="vertical"),
|
|
rx.badge("Max Age: ", State.age[1]),
|
|
),
|
|
rx.slider(
|
|
default_value=[18, 50],
|
|
min=18,
|
|
max=50,
|
|
on_value_commit=State.set_age, # pyright: ignore [reportAttributeAccessIssue]
|
|
),
|
|
align_items="left",
|
|
width="100%",
|
|
),
|
|
rx.vstack(
|
|
rx.hstack(
|
|
rx.badge("Min Sal: ", State.salary[0] // 1000000, "M"),
|
|
rx.divider(orientation="vertical"),
|
|
rx.badge("Max Sal: ", State.salary[1] // 1000000, "M"),
|
|
),
|
|
rx.slider(
|
|
default_value=[0, 25000000],
|
|
min=0,
|
|
max=25000000,
|
|
on_value_commit=State.set_salary, # pyright: ignore [reportAttributeAccessIssue]
|
|
),
|
|
align_items="left",
|
|
width="100%",
|
|
),
|
|
),
|
|
spacing="4",
|
|
),
|
|
width="100%",
|
|
)
|
|
|
|
for i in range(1, num + 1):
|
|
if i % 2 == 1:
|
|
app.add_page(comp1, route=f"page{i}")
|
|
else:
|
|
app.add_page(comp2, route=f"page{i}")
|
|
|
|
|
|
def AppWithOnePage():
|
|
"""A reflex app with one page."""
|
|
from rxconfig import config # pyright: ignore [reportMissingImports]
|
|
|
|
import reflex as rx
|
|
|
|
docs_url = "https://reflex.dev/docs/getting-started/introduction/"
|
|
filename = f"{config.app_name}/{config.app_name}.py"
|
|
|
|
class State(rx.State):
|
|
"""The app state."""
|
|
|
|
pass
|
|
|
|
def index() -> rx.Component:
|
|
return rx.center(
|
|
rx.input(
|
|
id="token", value=State.router.session.client_token, is_read_only=True
|
|
),
|
|
rx.vstack(
|
|
rx.heading("Welcome to Reflex!", size="9"),
|
|
rx.text("Get started by editing ", rx.code(filename)),
|
|
rx.button(
|
|
"Check out our docs!",
|
|
on_click=lambda: rx.redirect(docs_url),
|
|
size="4",
|
|
),
|
|
align="center",
|
|
spacing="7",
|
|
font_size="2em",
|
|
),
|
|
height="100vh",
|
|
)
|
|
|
|
app = rx.App(_state=rx.State)
|
|
app.add_page(index)
|
|
|
|
|
|
def AppWithTenPages():
|
|
"""A reflex app with 10 pages."""
|
|
import reflex as rx
|
|
|
|
app = rx.App(_state=rx.State)
|
|
render_multiple_pages(app, 10)
|
|
|
|
|
|
def AppWithHundredPages():
|
|
"""A reflex app with 100 pages."""
|
|
import reflex as rx
|
|
|
|
app = rx.App(_state=rx.State)
|
|
render_multiple_pages(app, 100)
|
|
|
|
|
|
def AppWithThousandPages():
|
|
"""A reflex app with Thousand pages."""
|
|
import reflex as rx
|
|
|
|
app = rx.App(_state=rx.State)
|
|
render_multiple_pages(app, 1000)
|
|
|
|
|
|
def AppWithTenThousandPages():
|
|
"""A reflex app with ten thousand pages."""
|
|
import reflex as rx
|
|
|
|
app = rx.App(_state=rx.State)
|
|
render_multiple_pages(app, 10000)
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def app_with_one_page(
|
|
tmp_path_factory,
|
|
) -> Generator[AppHarness, None, None]:
|
|
"""Create an app with 10000 pages at tmp_path via AppHarness.
|
|
|
|
Args:
|
|
tmp_path_factory: pytest tmp_path_factory fixture
|
|
|
|
Yields:
|
|
an AppHarness instance
|
|
"""
|
|
root = tmp_path_factory.mktemp("app1")
|
|
|
|
yield AppHarness.create(root=root, app_source=AppWithOnePage)
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def app_with_ten_pages(
|
|
tmp_path_factory,
|
|
) -> Generator[AppHarness, None, None]:
|
|
"""Create an app with 10 pages at tmp_path via AppHarness.
|
|
|
|
Args:
|
|
tmp_path_factory: pytest tmp_path_factory fixture
|
|
|
|
Yields:
|
|
an AppHarness instance
|
|
"""
|
|
root = tmp_path_factory.mktemp("app10")
|
|
yield AppHarness.create(
|
|
root=root,
|
|
app_source=functools.partial(
|
|
AppWithTenPages,
|
|
render_comp=render_multiple_pages, # pyright: ignore [reportCallIssue]
|
|
),
|
|
)
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def app_with_hundred_pages(
|
|
tmp_path_factory,
|
|
) -> Generator[AppHarness, None, None]:
|
|
"""Create an app with 100 pages at tmp_path via AppHarness.
|
|
|
|
Args:
|
|
tmp_path_factory: pytest tmp_path_factory fixture
|
|
|
|
Yields:
|
|
an AppHarness instance
|
|
"""
|
|
root = tmp_path_factory.mktemp("app100")
|
|
|
|
yield AppHarness.create(
|
|
root=root,
|
|
app_source=functools.partial(
|
|
AppWithHundredPages,
|
|
render_comp=render_multiple_pages, # pyright: ignore [reportCallIssue]
|
|
),
|
|
)
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def app_with_thousand_pages(
|
|
tmp_path_factory,
|
|
) -> Generator[AppHarness, None, None]:
|
|
"""Create an app with 1000 pages at tmp_path via AppHarness.
|
|
|
|
Args:
|
|
tmp_path_factory: pytest tmp_path_factory fixture
|
|
|
|
Yields:
|
|
an AppHarness instance
|
|
"""
|
|
root = tmp_path_factory.mktemp("app1000")
|
|
|
|
yield AppHarness.create(
|
|
root=root,
|
|
app_source=functools.partial(
|
|
AppWithThousandPages,
|
|
render_comp=render_multiple_pages, # pyright: ignore [reportCallIssue]
|
|
),
|
|
)
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def app_with_ten_thousand_pages(
|
|
tmp_path_factory,
|
|
) -> Generator[AppHarness, None, None]:
|
|
"""Create an app with 10000 pages at tmp_path via AppHarness.
|
|
|
|
Args:
|
|
tmp_path_factory: pytest tmp_path_factory fixture
|
|
|
|
Yields:
|
|
running AppHarness instance
|
|
"""
|
|
root = tmp_path_factory.mktemp("app10000")
|
|
|
|
yield AppHarness.create(
|
|
root=root,
|
|
app_source=functools.partial(
|
|
AppWithTenThousandPages,
|
|
render_comp=render_multiple_pages, # pyright: ignore [reportCallIssue]
|
|
),
|
|
)
|
|
|
|
|
|
@pytest.mark.skipif(constants.IS_WINDOWS, reason=WINDOWS_SKIP_REASON)
|
|
@pytest.mark.benchmark(
|
|
group="Compile time of varying page numbers",
|
|
timer=time.perf_counter,
|
|
disable_gc=True,
|
|
warmup=False,
|
|
)
|
|
def test_app_1_compile_time_cold(benchmark, app_with_one_page):
|
|
"""Test the compile time on a cold start for an app with 1 page.
|
|
|
|
Args:
|
|
benchmark: The benchmark fixture.
|
|
app_with_one_page: The app harness.
|
|
"""
|
|
|
|
def setup():
|
|
with chdir(app_with_one_page.app_path):
|
|
utils.empty_dir(web_pages, keep_files=["_app.js"])
|
|
app_with_one_page._initialize_app()
|
|
build.setup_frontend(app_with_one_page.app_path)
|
|
|
|
def benchmark_fn():
|
|
with chdir(app_with_one_page.app_path):
|
|
app_with_one_page.app_instance._compile()
|
|
|
|
benchmark.pedantic(benchmark_fn, setup=setup, rounds=5)
|
|
app_with_one_page._reload_state_module()
|
|
|
|
|
|
@pytest.mark.benchmark(
|
|
group="Compile time of varying page numbers",
|
|
min_rounds=5,
|
|
timer=time.perf_counter,
|
|
disable_gc=True,
|
|
warmup=False,
|
|
)
|
|
def test_app_1_compile_time_warm(benchmark, app_with_one_page):
|
|
"""Test the compile time on a warm start for an app with 1 page.
|
|
|
|
Args:
|
|
benchmark: The benchmark fixture.
|
|
app_with_one_page: The app harness.
|
|
"""
|
|
with chdir(app_with_one_page.app_path):
|
|
app_with_one_page._initialize_app()
|
|
build.setup_frontend(app_with_one_page.app_path)
|
|
|
|
def benchmark_fn():
|
|
with chdir(app_with_one_page.app_path):
|
|
app_with_one_page.app_instance._compile()
|
|
|
|
benchmark(benchmark_fn)
|
|
app_with_one_page._reload_state_module()
|
|
|
|
|
|
@pytest.mark.skipif(constants.IS_WINDOWS, reason=WINDOWS_SKIP_REASON)
|
|
@pytest.mark.benchmark(
|
|
group="Compile time of varying page numbers",
|
|
timer=time.perf_counter,
|
|
disable_gc=True,
|
|
warmup=False,
|
|
)
|
|
def test_app_10_compile_time_cold(benchmark, app_with_ten_pages):
|
|
"""Test the compile time on a cold start for an app with 10 page.
|
|
|
|
Args:
|
|
benchmark: The benchmark fixture.
|
|
app_with_ten_pages: The app harness.
|
|
"""
|
|
|
|
def setup():
|
|
with chdir(app_with_ten_pages.app_path):
|
|
utils.empty_dir(web_pages, keep_files=["_app.js"])
|
|
app_with_ten_pages._initialize_app()
|
|
build.setup_frontend(app_with_ten_pages.app_path)
|
|
|
|
def benchmark_fn():
|
|
with chdir(app_with_ten_pages.app_path):
|
|
app_with_ten_pages.app_instance._compile()
|
|
|
|
benchmark.pedantic(benchmark_fn, setup=setup, rounds=5)
|
|
app_with_ten_pages._reload_state_module()
|
|
|
|
|
|
@pytest.mark.benchmark(
|
|
group="Compile time of varying page numbers",
|
|
min_rounds=5,
|
|
timer=time.perf_counter,
|
|
disable_gc=True,
|
|
warmup=False,
|
|
)
|
|
def test_app_10_compile_time_warm(benchmark, app_with_ten_pages):
|
|
"""Test the compile time on a warm start for an app with 10 page.
|
|
|
|
Args:
|
|
benchmark: The benchmark fixture.
|
|
app_with_ten_pages: The app harness.
|
|
"""
|
|
with chdir(app_with_ten_pages.app_path):
|
|
app_with_ten_pages._initialize_app()
|
|
build.setup_frontend(app_with_ten_pages.app_path)
|
|
|
|
def benchmark_fn():
|
|
with chdir(app_with_ten_pages.app_path):
|
|
app_with_ten_pages.app_instance._compile()
|
|
|
|
benchmark(benchmark_fn)
|
|
app_with_ten_pages._reload_state_module()
|
|
|
|
|
|
@pytest.mark.skipif(constants.IS_WINDOWS, reason=WINDOWS_SKIP_REASON)
|
|
@pytest.mark.benchmark(
|
|
group="Compile time of varying page numbers",
|
|
timer=time.perf_counter,
|
|
disable_gc=True,
|
|
warmup=False,
|
|
)
|
|
def test_app_100_compile_time_cold(benchmark, app_with_hundred_pages):
|
|
"""Test the compile time on a cold start for an app with 100 page.
|
|
|
|
Args:
|
|
benchmark: The benchmark fixture.
|
|
app_with_hundred_pages: The app harness.
|
|
"""
|
|
|
|
def setup():
|
|
with chdir(app_with_hundred_pages.app_path):
|
|
utils.empty_dir(web_pages, keep_files=["_app.js"])
|
|
app_with_hundred_pages._initialize_app()
|
|
build.setup_frontend(app_with_hundred_pages.app_path)
|
|
|
|
def benchmark_fn():
|
|
with chdir(app_with_hundred_pages.app_path):
|
|
app_with_hundred_pages.app_instance._compile()
|
|
|
|
benchmark.pedantic(benchmark_fn, setup=setup, rounds=5)
|
|
app_with_hundred_pages._reload_state_module()
|
|
|
|
|
|
@pytest.mark.benchmark(
|
|
group="Compile time of varying page numbers",
|
|
min_rounds=5,
|
|
timer=time.perf_counter,
|
|
disable_gc=True,
|
|
warmup=False,
|
|
)
|
|
def test_app_100_compile_time_warm(benchmark, app_with_hundred_pages):
|
|
"""Test the compile time on a warm start for an app with 100 page.
|
|
|
|
Args:
|
|
benchmark: The benchmark fixture.
|
|
app_with_hundred_pages: The app harness.
|
|
"""
|
|
with chdir(app_with_hundred_pages.app_path):
|
|
app_with_hundred_pages._initialize_app()
|
|
build.setup_frontend(app_with_hundred_pages.app_path)
|
|
|
|
def benchmark_fn():
|
|
with chdir(app_with_hundred_pages.app_path):
|
|
app_with_hundred_pages.app_instance._compile()
|
|
|
|
benchmark(benchmark_fn)
|
|
app_with_hundred_pages._reload_state_module()
|
|
|
|
|
|
@pytest.mark.skipif(constants.IS_WINDOWS, reason=WINDOWS_SKIP_REASON)
|
|
@pytest.mark.benchmark(
|
|
group="Compile time of varying page numbers",
|
|
timer=time.perf_counter,
|
|
disable_gc=True,
|
|
warmup=False,
|
|
)
|
|
def test_app_1000_compile_time_cold(benchmark, app_with_thousand_pages):
|
|
"""Test the compile time on a cold start for an app with 1000 page.
|
|
|
|
Args:
|
|
benchmark: The benchmark fixture.
|
|
app_with_thousand_pages: The app harness.
|
|
"""
|
|
|
|
def setup():
|
|
with chdir(app_with_thousand_pages.app_path):
|
|
utils.empty_dir(web_pages, keep_files=["_app.js"])
|
|
app_with_thousand_pages._initialize_app()
|
|
build.setup_frontend(app_with_thousand_pages.app_path)
|
|
|
|
def benchmark_fn():
|
|
with chdir(app_with_thousand_pages.app_path):
|
|
app_with_thousand_pages.app_instance._compile()
|
|
|
|
benchmark.pedantic(benchmark_fn, setup=setup, rounds=5)
|
|
app_with_thousand_pages._reload_state_module()
|
|
|
|
|
|
@pytest.mark.benchmark(
|
|
group="Compile time of varying page numbers",
|
|
min_rounds=5,
|
|
timer=time.perf_counter,
|
|
disable_gc=True,
|
|
warmup=False,
|
|
)
|
|
def test_app_1000_compile_time_warm(benchmark, app_with_thousand_pages):
|
|
"""Test the compile time on a warm start for an app with 1000 page.
|
|
|
|
Args:
|
|
benchmark: The benchmark fixture.
|
|
app_with_thousand_pages: The app harness.
|
|
"""
|
|
with chdir(app_with_thousand_pages.app_path):
|
|
app_with_thousand_pages._initialize_app()
|
|
build.setup_frontend(app_with_thousand_pages.app_path)
|
|
|
|
def benchmark_fn():
|
|
with chdir(app_with_thousand_pages.app_path):
|
|
app_with_thousand_pages.app_instance._compile()
|
|
|
|
benchmark(benchmark_fn)
|
|
app_with_thousand_pages._reload_state_module()
|
|
|
|
|
|
@pytest.mark.skip
|
|
@pytest.mark.benchmark(
|
|
group="Compile time of varying page numbers",
|
|
timer=time.perf_counter,
|
|
disable_gc=True,
|
|
warmup=False,
|
|
)
|
|
def test_app_10000_compile_time_cold(benchmark, app_with_ten_thousand_pages):
|
|
"""Test the compile time on a cold start for an app with 10000 page.
|
|
|
|
Args:
|
|
benchmark: The benchmark fixture.
|
|
app_with_ten_thousand_pages: The app harness.
|
|
"""
|
|
|
|
def setup():
|
|
with chdir(app_with_ten_thousand_pages.app_path):
|
|
utils.empty_dir(web_pages, keep_files=["_app.js"])
|
|
app_with_ten_thousand_pages._initialize_app()
|
|
build.setup_frontend(app_with_ten_thousand_pages.app_path)
|
|
|
|
def benchmark_fn():
|
|
with chdir(app_with_ten_thousand_pages.app_path):
|
|
app_with_ten_thousand_pages.app_instance._compile()
|
|
|
|
benchmark.pedantic(benchmark_fn, setup=setup, rounds=5)
|
|
app_with_ten_thousand_pages._reload_state_module()
|
|
|
|
|
|
@pytest.mark.skip
|
|
@pytest.mark.benchmark(
|
|
group="Compile time of varying page numbers",
|
|
min_rounds=5,
|
|
timer=time.perf_counter,
|
|
disable_gc=True,
|
|
warmup=False,
|
|
)
|
|
def test_app_10000_compile_time_warm(benchmark, app_with_ten_thousand_pages):
|
|
"""Test the compile time on a warm start for an app with 10000 page.
|
|
|
|
Args:
|
|
benchmark: The benchmark fixture.
|
|
app_with_ten_thousand_pages: The app harness.
|
|
"""
|
|
|
|
def benchmark_fn():
|
|
with chdir(app_with_ten_thousand_pages.app_path):
|
|
app_with_ten_thousand_pages.app_instance._compile()
|
|
|
|
benchmark(benchmark_fn)
|
|
app_with_ten_thousand_pages._reload_state_module()
|