diff --git a/.github/workflows/integration_app_harness.yml b/.github/workflows/integration_app_harness.yml index ed74ac39d..18bc61f6f 100644 --- a/.github/workflows/integration_app_harness.yml +++ b/.github/workflows/integration_app_harness.yml @@ -19,7 +19,7 @@ jobs: strategy: matrix: state_manager: [ "redis", "memory" ] - python-version: ["3.11.5", "3.12.0"] + python-version: ["3.8.18", "3.11.5", "3.12.0"] runs-on: ubuntu-latest services: # Label used to access the service container diff --git a/integration/init-test/Dockerfile b/integration/init-test/Dockerfile index 8bc6e4b13..aa11344b1 100644 --- a/integration/init-test/Dockerfile +++ b/integration/init-test/Dockerfile @@ -1,7 +1,8 @@ -FROM python:3.11 +FROM python:3.8 ARG USERNAME=kerrigan RUN useradd -m $USERNAME +RUN apt-get update && apt-get install -y redis && rm -rf /var/lib/apt/lists/* USER $USERNAME WORKDIR /home/$USERNAME diff --git a/integration/init-test/in_docker_test_script.sh b/integration/init-test/in_docker_test_script.sh index beecfc91c..733cbf4ad 100755 --- a/integration/init-test/in_docker_test_script.sh +++ b/integration/init-test/in_docker_test_script.sh @@ -2,6 +2,7 @@ set -euxo pipefail +SCRIPTPATH="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" export TELEMETRY_ENABLED=false function do_export () { @@ -11,6 +12,15 @@ function do_export () { rm -rf ~/.local/share/reflex ~/"$template"/.web reflex init --template "$template" reflex export + ( + cd "$SCRIPTPATH/../.." + scripts/integration.sh ~/"$template" dev + pkill -9 -f 'next-server|python3' || true + sleep 10 + REDIS_URL=redis://localhost scripts/integration.sh ~/"$template" prod + pkill -9 -f 'next-server|python3' || true + sleep 10 + ) } echo "Preparing test project dir" @@ -20,6 +30,8 @@ source ~/venv/bin/activate echo "Installing reflex from local repo code" pip install /reflex-repo +redis-server & + echo "Running reflex init in test project dir" do_export blank do_export sidebar \ No newline at end of file diff --git a/integration/test_call_script.py b/integration/test_call_script.py index 3aea81e10..607d467c7 100644 --- a/integration/test_call_script.py +++ b/integration/test_call_script.py @@ -12,6 +12,8 @@ from reflex.testing import AppHarness def CallScript(): """A test app for browser javascript integration.""" + from typing import Dict, List, Optional, Union + import reflex as rx inline_scripts = """ @@ -37,7 +39,7 @@ def CallScript(): external_scripts = inline_scripts.replace("inline", "external") class CallScriptState(rx.State): - results: list[str | dict | list | None] = [] + results: List[Optional[Union[str, Dict, List]]] = [] inline_counter: int = 0 external_counter: int = 0 diff --git a/integration/test_dynamic_routes.py b/integration/test_dynamic_routes.py index 97a2a7070..d70d72d07 100644 --- a/integration/test_dynamic_routes.py +++ b/integration/test_dynamic_routes.py @@ -1,4 +1,6 @@ """Integration tests for dynamic route page behavior.""" +from __future__ import annotations + from typing import Callable, Coroutine, Generator, Type from urllib.parse import urlsplit @@ -12,10 +14,12 @@ from .utils import poll_for_navigation def DynamicRoute(): """App for testing dynamic routes.""" + from typing import List + import reflex as rx class DynamicState(rx.State): - order: list[str] = [] + order: List[str] = [] page_id: str = "" def on_load(self): diff --git a/integration/test_event_actions.py b/integration/test_event_actions.py index 67605639a..59ee5f537 100644 --- a/integration/test_event_actions.py +++ b/integration/test_event_actions.py @@ -1,4 +1,5 @@ """Ensure stopPropagation and preventDefault work as expected.""" +from __future__ import annotations import asyncio from typing import Callable, Coroutine, Generator @@ -11,10 +12,12 @@ from reflex.testing import AppHarness, WebDriver def TestEventAction(): """App for testing event_actions.""" + from typing import List, Optional + import reflex as rx class EventActionState(rx.State): - order: list[str] + order: List[str] def on_click(self, ev): self.order.append(f"on_click:{ev}") @@ -27,7 +30,7 @@ def TestEventAction(): tag = "EventFiringComponent" - def _get_custom_code(self) -> str | None: + def _get_custom_code(self) -> Optional[str]: return """ function EventFiringComponent(props) { return ( diff --git a/integration/test_event_chain.py b/integration/test_event_chain.py index da9a197b3..194d04b11 100644 --- a/integration/test_event_chain.py +++ b/integration/test_event_chain.py @@ -1,4 +1,5 @@ """Ensure that Event Chains are properly queued and handled between frontend and backend.""" +from __future__ import annotations from typing import Generator @@ -14,6 +15,7 @@ def EventChain(): """App with chained event handlers.""" import asyncio import time + from typing import List import reflex as rx @@ -21,7 +23,7 @@ def EventChain(): MANY_EVENTS = 50 class State(rx.State): - event_order: list[str] = [] + event_order: List[str] = [] interim_value: str = "" def event_no_args(self): diff --git a/integration/test_form_submit.py b/integration/test_form_submit.py index eab0253ca..a6b2c2eb3 100644 --- a/integration/test_form_submit.py +++ b/integration/test_form_submit.py @@ -17,14 +17,16 @@ def FormSubmit(form_component): Args: form_component: The str name of the form component to use. """ + from typing import Dict, List + import reflex as rx class FormState(rx.State): - form_data: dict = {} + form_data: Dict = {} - var_options: list[str] = ["option3", "option4"] + var_options: List[str] = ["option3", "option4"] - def form_submit(self, form_data: dict): + def form_submit(self, form_data: Dict): self.form_data = form_data app = rx.App(state=rx.State) @@ -74,14 +76,16 @@ def FormSubmitName(form_component): Args: form_component: The str name of the form component to use. """ + from typing import Dict, List + import reflex as rx class FormState(rx.State): - form_data: dict = {} + form_data: Dict = {} val: str = "foo" - options: list[str] = ["option1", "option2"] + options: List[str] = ["option1", "option2"] - def form_submit(self, form_data: dict): + def form_submit(self, form_data: Dict): self.form_data = form_data app = rx.App(state=rx.State) diff --git a/integration/test_state_inheritance.py b/integration/test_state_inheritance.py index cdbe30321..6b3c99ca1 100644 --- a/integration/test_state_inheritance.py +++ b/integration/test_state_inheritance.py @@ -1,4 +1,5 @@ """Test state inheritance.""" +from __future__ import annotations from contextlib import suppress from typing import Generator diff --git a/integration/test_upload.py b/integration/test_upload.py index c703a6747..b2dae4bde 100644 --- a/integration/test_upload.py +++ b/integration/test_upload.py @@ -13,19 +13,21 @@ from reflex.testing import AppHarness, WebDriver def UploadFile(): """App for testing dynamic routes.""" + from typing import Dict, List + import reflex as rx class UploadState(rx.State): - _file_data: dict[str, str] = {} - event_order: list[str] = [] - progress_dicts: list[dict] = [] + _file_data: Dict[str, str] = {} + event_order: List[str] = [] + progress_dicts: List[dict] = [] - async def handle_upload(self, files: list[rx.UploadFile]): + async def handle_upload(self, files: List[rx.UploadFile]): for file in files: upload_data = await file.read() self._file_data[file.filename or ""] = upload_data.decode("utf-8") - async def handle_upload_secondary(self, files: list[rx.UploadFile]): + async def handle_upload_secondary(self, files: List[rx.UploadFile]): for file in files: upload_data = await file.read() self._file_data[file.filename or ""] = upload_data.decode("utf-8") diff --git a/integration/test_var_operations.py b/integration/test_var_operations.py index f0f53ab83..768aa3d34 100644 --- a/integration/test_var_operations.py +++ b/integration/test_var_operations.py @@ -11,6 +11,8 @@ from reflex.testing import AppHarness def VarOperations(): """App with var operations.""" + from typing import Dict, List + import reflex as rx class VarOperationState(rx.State): @@ -19,15 +21,15 @@ def VarOperations(): int_var3: int = 7 float_var1: float = 10.5 float_var2: float = 5.5 - list1: list = [1, 2] - list2: list = [3, 4] - list3: list = ["first", "second", "third"] + list1: List = [1, 2] + list2: List = [3, 4] + list3: List = ["first", "second", "third"] str_var1: str = "first" str_var2: str = "second" str_var3: str = "ThIrD" str_var4: str = "a long string" - dict1: dict = {1: 2} - dict2: dict = {3: 4} + dict1: Dict = {1: 2} + dict2: Dict = {3: 4} html_str: str = "