From 29d0013868a9968d3bdb316066f24ab8a8c183c0 Mon Sep 17 00:00:00 2001 From: Masen Furer Date: Wed, 27 Sep 2023 07:46:59 -0700 Subject: [PATCH] random-number-range example --- random-number-range/.gitignore | 4 + random-number-range/assets/favicon.ico | Bin 0 -> 15086 bytes .../random_number_range/__init__.py | 0 .../random_number_range.py | 148 ++++++++++++++++++ random-number-range/requirements.txt | 1 + random-number-range/rxconfig.py | 5 + 6 files changed, 158 insertions(+) create mode 100644 random-number-range/.gitignore create mode 100644 random-number-range/assets/favicon.ico create mode 100644 random-number-range/random_number_range/__init__.py create mode 100644 random-number-range/random_number_range/random_number_range.py create mode 100644 random-number-range/requirements.txt create mode 100644 random-number-range/rxconfig.py diff --git a/random-number-range/.gitignore b/random-number-range/.gitignore new file mode 100644 index 00000000..eab0d4b0 --- /dev/null +++ b/random-number-range/.gitignore @@ -0,0 +1,4 @@ +*.db +*.py[cod] +.web +__pycache__/ \ No newline at end of file diff --git a/random-number-range/assets/favicon.ico b/random-number-range/assets/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..609f6abcbeb0fec5157b54a36d7b2aeb759f9e1b GIT binary patch literal 15086 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 str: + return ", ".join(str(x) for x in self._last_values[-10:]) + + def balance(self): + max_magnitude = max(abs(x) for x in self.rrange) + self.rrange = [-max_magnitude, max_magnitude] + + +class BackgroundState(BaseState): + running: bool = False + loading: bool = False + _n_tasks: int = 0 + + @rx.background + async def run_task(self): + async with self: + if self._n_tasks > 0: + return + self._n_tasks += 1 + + while True: + async with self: + self.loading = True + + # Simulate long running API call + await asyncio.sleep(self.delay) + + async with self: + last_value = random.randint(*self.rrange) + self.total += last_value + self._last_values = self._last_values[-9:] + [last_value] + self.loading = False + if not self.running: + break + + async with self: + self._n_tasks -= 1 + + def set_running(self, value: bool): + self.running = value + if value: + return BackgroundState.run_task + + def single_step(self): + self.running = False + return BackgroundState.run_task + + +class ChainState(BaseState): + running: bool = False + loading: bool = False + + async def run_task(self): + self.loading = True + yield + + # Simulate long running API call + await asyncio.sleep(self.delay) + + last_value = random.randint(*self.rrange) + self.total += last_value + self._last_values = self._last_values[-9:] + [last_value] + self.loading = False + + if self.running: + yield ChainState.run_task + + def set_running(self, value: bool): + self.running = value + if self.running: + return ChainState.run_task + + def single_step(self): + self.running = False + return ChainState.run_task + + +other_links = { + "Chain Events": lambda State: rx.link("Background Task Version", href="/background", on_click=State.set_running(False)), + "Background Task": lambda State: rx.link("Chain Event Version", href="/chain", on_click=State.set_running(False)), +} + + +def random_numbers_in_range(State, mode: str) -> rx.Component: + return rx.center( + rx.vstack( + rx.heading(f"Random Numbers in Range"), + rx.heading(f"{mode} version", font_size="1.5em"), + other_links[mode](State), + rx.hstack( + rx.text("Min: ", State.rrange[0], padding_right="3em"), + rx.button("Balance", on_click=State.balance), + rx.text("Max: ", State.rrange[1], padding_left="3em"), + ), + rx.range_slider(value=State.rrange, on_change=State.set_rrange, min_=-100, max_=100), + rx.hstack( + rx.text("Last 10 values: ", State.last_values), + rx.cond(State.loading, rx.spinner()), + ), + rx.hstack( + rx.text("Total: ", State.total), + rx.button("Clear", on_click=lambda: State.set_total(0)), + ), + rx.hstack( + rx.vstack( + rx.text("Run", font_size="0.7em"), + rx.switch(is_checked=State.running, on_change=State.set_running), + ), + rx.vstack( + rx.text("Delay (sec)", font_size="0.7em"), + rx.select(*[rx.option(x) for x in range(1, 5)], value=State.delay.to(str), on_change=State.set_delay), + padding_right="3em", + ), + rx.button("Single Step", on_click=State.single_step), + align_items="flex-start", + ), + width="50vw", + ), + ) + + +app = rx.App() +app.add_page(rx.fragment(on_mount=rx.redirect("/chain")), route="/") +app.add_page(random_numbers_in_range(ChainState, "Chain Events"), route="/chain") +app.add_page(random_numbers_in_range(BackgroundState, "Background Task"), route="/background") +app.compile() diff --git a/random-number-range/requirements.txt b/random-number-range/requirements.txt new file mode 100644 index 00000000..21e07bd4 --- /dev/null +++ b/random-number-range/requirements.txt @@ -0,0 +1 @@ +reflex>=0.2.8 diff --git a/random-number-range/rxconfig.py b/random-number-range/rxconfig.py new file mode 100644 index 00000000..b36d140e --- /dev/null +++ b/random-number-range/rxconfig.py @@ -0,0 +1,5 @@ +import reflex as rx + +config = rx.Config( + app_name="random_number_range", +) \ No newline at end of file