diff --git a/.github/workflows/benchmarks.yml b/.github/workflows/benchmarks.yml index f743b7cbd..e689e4514 100644 --- a/.github/workflows/benchmarks.yml +++ b/.github/workflows/benchmarks.yml @@ -81,15 +81,11 @@ jobs: matrix: # Show OS combos first in GUI os: [ubuntu-latest, windows-latest, macos-latest] - python-version: ['3.9.18', '3.10.13', '3.11.5', '3.12.0'] + python-version: ['3.10.13', '3.11.5', '3.12.0'] exclude: - os: windows-latest python-version: '3.10.13' - - os: windows-latest - python-version: '3.9.18' # keep only one python version for MacOS - - os: macos-latest - python-version: '3.9.18' - os: macos-latest python-version: '3.10.13' - os: macos-latest @@ -97,8 +93,6 @@ jobs: include: - os: windows-latest python-version: '3.10.11' - - os: windows-latest - python-version: '3.9.13' runs-on: ${{ matrix.os }} steps: diff --git a/.github/workflows/check_outdated_dependencies.yml b/.github/workflows/check_outdated_dependencies.yml index a7465defb..ae40a95e1 100644 --- a/.github/workflows/check_outdated_dependencies.yml +++ b/.github/workflows/check_outdated_dependencies.yml @@ -16,7 +16,7 @@ jobs: - uses: ./.github/actions/setup_build_env with: - python-version: '3.9' + python-version: '3.10' run-poetry-install: true create-venv-at-path: .venv diff --git a/.github/workflows/integration_tests.yml b/.github/workflows/integration_tests.yml index b2304d463..49a8d1c49 100644 --- a/.github/workflows/integration_tests.yml +++ b/.github/workflows/integration_tests.yml @@ -43,17 +43,13 @@ jobs: matrix: # Show OS combos first in GUI os: [ubuntu-latest, windows-latest] - python-version: ['3.9.18', '3.10.13', '3.11.5', '3.12.0', '3.13.0'] + python-version: ['3.10.13', '3.11.5', '3.12.0', '3.13.0'] exclude: - os: windows-latest python-version: '3.10.13' - - os: windows-latest - python-version: '3.9.18' include: - os: windows-latest python-version: '3.10.11' - - os: windows-latest - python-version: '3.9.13' runs-on: ${{ matrix.os }} steps: diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index 25f5723f3..b5cf3d0d7 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -28,18 +28,14 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, windows-latest] - python-version: ['3.9.18', '3.10.13', '3.11.5', '3.12.0', '3.13.0'] + python-version: ['3.10.13', '3.11.5', '3.12.0', '3.13.0'] # Windows is a bit behind on Python version availability in Github exclude: - os: windows-latest python-version: '3.10.13' - - os: windows-latest - python-version: '3.9.18' include: - os: windows-latest python-version: '3.10.11' - - os: windows-latest - python-version: '3.9.13' runs-on: ${{ matrix.os }} # Service containers to run with `runner-job` @@ -88,8 +84,8 @@ jobs: strategy: fail-fast: false matrix: - # Note: py39, py310 versions chosen due to available arm64 darwin builds. - python-version: ['3.9.13', '3.10.11', '3.11.5', '3.12.0', '3.13.0'] + # Note: py310 version chosen due to available arm64 darwin builds. + python-version: ['3.10.11', '3.11.5', '3.12.0', '3.13.0'] runs-on: macos-latest steps: - uses: actions/checkout@v4 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fc8398013..aed576c42 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,7 +8,7 @@ Here is a quick guide on how to run Reflex repo locally so you can start contrib **Prerequisites:** -- Python >= 3.9 +- Python >= 3.10 - Poetry version >= 1.4.0 and add it to your path (see [Poetry Docs](https://python-poetry.org/docs/#installation) for more info). **1. Fork this repository:** @@ -87,7 +87,7 @@ poetry run ruff format . ``` Consider installing git pre-commit hooks so Ruff, Pyright, Darglint and `make_pyi` will run automatically before each commit. -Note that pre-commit will only be installed when you use a Python version >= 3.9. +Note that pre-commit will only be installed when you use a Python version >= 3.10. ``` bash pre-commit install diff --git a/README.md b/README.md index 5e098b2d3..5174d563e 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ See our [architecture page](https://reflex.dev/blog/2024-03-21-reflex-architectu ## ⚙️ Installation -Open a terminal and run (Requires Python 3.9+): +Open a terminal and run (Requires Python 3.10+): ```bash pip install reflex diff --git a/docs/de/README.md b/docs/de/README.md index 9931c24cc..6d2d69e94 100644 --- a/docs/de/README.md +++ b/docs/de/README.md @@ -34,7 +34,7 @@ Auf unserer [Architektur-Seite](https://reflex.dev/blog/2024-03-21-reflex-archit ## ⚙️ Installation -Öffne ein Terminal und führe den folgenden Befehl aus (benötigt Python 3.9+): +Öffne ein Terminal und führe den folgenden Befehl aus (benötigt Python 3.10+): ```bash pip install reflex diff --git a/docs/es/README.md b/docs/es/README.md index 15ce63335..538192e4b 100644 --- a/docs/es/README.md +++ b/docs/es/README.md @@ -35,7 +35,7 @@ Consulta nuestra [página de arquitectura](https://reflex.dev/blog/2024-03-21-re ## ⚙️ Instalación -Abra un terminal y ejecute (Requiere Python 3.9+): +Abra un terminal y ejecute (Requiere Python 3.10+): ```bash pip install reflex diff --git a/docs/in/README.md b/docs/in/README.md index ebc4155f4..81b1106ff 100644 --- a/docs/in/README.md +++ b/docs/in/README.md @@ -35,7 +35,7 @@ Reflex के अंदर के कामकाज को जानने क ## ⚙️ इंस्टॉलेशन (Installation) -एक टर्मिनल खोलें और चलाएं (Python 3.9+ की आवश्यकता है): +एक टर्मिनल खोलें और चलाएं (Python 3.10+ की आवश्यकता है): ```bash pip install reflex diff --git a/docs/it/README.md b/docs/it/README.md index 92438f696..cd6f24dd8 100644 --- a/docs/it/README.md +++ b/docs/it/README.md @@ -22,7 +22,7 @@ ## ⚙️ Installazione -Apri un terminale ed esegui (Richiede Python 3.9+): +Apri un terminale ed esegui (Richiede Python 3.10+): ```bash pip install reflex diff --git a/docs/ja/README.md b/docs/ja/README.md index 0a7ab0d53..941bef601 100644 --- a/docs/ja/README.md +++ b/docs/ja/README.md @@ -37,7 +37,7 @@ Reflex がどのように動作しているかを知るには、[アーキテク ## ⚙️ インストール -ターミナルを開いて以下のコマンドを実行してください。(Python 3.9 以上が必要です。): +ターミナルを開いて以下のコマンドを実行してください。(Python 3.10 以上が必要です。): ```bash pip install reflex diff --git a/docs/kr/README.md b/docs/kr/README.md index a92fcd0c5..57bb43794 100644 --- a/docs/kr/README.md +++ b/docs/kr/README.md @@ -20,7 +20,7 @@ --- ## ⚙️ 설치 -터미널을 열고 실행하세요. (Python 3.9+ 필요): +터미널을 열고 실행하세요. (Python 3.10+ 필요): ```bash pip install reflex diff --git a/docs/pe/README.md b/docs/pe/README.md index 3a0ba044b..867b543bc 100644 --- a/docs/pe/README.md +++ b/docs/pe/README.md @@ -34,7 +34,7 @@ ## ⚙️ Installation - نصب و راه اندازی -یک ترمینال را باز کنید و اجرا کنید (نیازمند Python 3.9+): +یک ترمینال را باز کنید و اجرا کنید (نیازمند Python 3.10+): ```bash pip install reflex diff --git a/docs/pt/pt_br/README.md b/docs/pt/pt_br/README.md index 184b668bc..8abfaebde 100644 --- a/docs/pt/pt_br/README.md +++ b/docs/pt/pt_br/README.md @@ -21,7 +21,7 @@ --- ## ⚙️ Instalação -Abra um terminal e execute (Requer Python 3.9+): +Abra um terminal e execute (Requer Python 3.10+): ```bash pip install reflex diff --git a/docs/tr/README.md b/docs/tr/README.md index 376547e01..afb8ae5b9 100644 --- a/docs/tr/README.md +++ b/docs/tr/README.md @@ -24,7 +24,7 @@ ## ⚙️ Kurulum -Bir terminal açın ve çalıştırın (Python 3.9+ gerekir): +Bir terminal açın ve çalıştırın (Python 3.10+ gerekir): ```bash pip install reflex diff --git a/docs/vi/README.md b/docs/vi/README.md index df7a31530..53fcad936 100644 --- a/docs/vi/README.md +++ b/docs/vi/README.md @@ -34,7 +34,7 @@ Các tính năng chính: ## ⚙️ Cài đặt -Mở cửa sổ lệnh và chạy (Yêu cầu Python phiên bản 3.9+): +Mở cửa sổ lệnh và chạy (Yêu cầu Python phiên bản 3.10+): ```bash pip install reflex diff --git a/docs/zh/zh_cn/README.md b/docs/zh/zh_cn/README.md index e114bc1e2..efaec0ca5 100644 --- a/docs/zh/zh_cn/README.md +++ b/docs/zh/zh_cn/README.md @@ -34,7 +34,7 @@ Reflex 是一个使用纯Python构建全栈web应用的库。 ## ⚙️ 安装 -打开一个终端并且运行(要求Python3.9+): +打开一个终端并且运行(要求Python3.10+): ```bash pip install reflex diff --git a/docs/zh/zh_tw/README.md b/docs/zh/zh_tw/README.md index 83f6b2ae2..6161e17d0 100644 --- a/docs/zh/zh_tw/README.md +++ b/docs/zh/zh_tw/README.md @@ -36,7 +36,7 @@ Reflex 是一個可以用純 Python 構建全端網頁應用程式的函式庫 ## ⚙️ 安裝 -開啟一個終端機並且執行 (需要 Python 3.9+): +開啟一個終端機並且執行 (需要 Python 3.10+): ```bash pip install reflex diff --git a/pyproject.toml b/pyproject.toml index 8fd1886f0..ca2f15894 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,7 +19,7 @@ classifiers = ["Development Status :: 4 - Beta"] packages = [{ include = "reflex" }] [tool.poetry.dependencies] -python = "^3.9" +python = "^3.10" fastapi = ">=0.96.0,!=0.111.0,!=0.111.1" gunicorn = ">=20.1.0,<24.0" jinja2 = ">=3.1.2,<4.0" diff --git a/reflex/.templates/jinja/custom_components/pyproject.toml.jinja2 b/reflex/.templates/jinja/custom_components/pyproject.toml.jinja2 index a5239f33b..abfd998fd 100644 --- a/reflex/.templates/jinja/custom_components/pyproject.toml.jinja2 +++ b/reflex/.templates/jinja/custom_components/pyproject.toml.jinja2 @@ -8,7 +8,7 @@ version = "0.0.1" description = "Reflex custom component {{ module_name }}" readme = "README.md" license = { text = "Apache-2.0" } -requires-python = ">=3.9" +requires-python = ">=3.10" authors = [{ name = "", email = "YOUREMAIL@domain.com" }] keywords = ["reflex","reflex-custom-components"] diff --git a/reflex/__init__.py b/reflex/__init__.py index 0be568b1a..0de3131a1 100644 --- a/reflex/__init__.py +++ b/reflex/__init__.py @@ -367,19 +367,4 @@ getattr, __dir__, __all__ = lazy_loader.attach( def __getattr__(name): - if name == "chakra": - from reflex.utils import console - - console.deprecate( - "rx.chakra", - reason="and moved to a separate package. " - "To continue using Chakra UI components, install the `reflex-chakra` package via `pip install " - "reflex-chakra`.", - deprecation_version="0.6.0", - removal_version="0.7.0", - dedupe=True, - ) - import reflex_chakra as rc - - return rc return getattr(name) diff --git a/reflex/components/component.py b/reflex/components/component.py index c1d4cbc80..527e280e5 100644 --- a/reflex/components/component.py +++ b/reflex/components/component.py @@ -23,8 +23,6 @@ from typing import ( Union, ) -from typing_extensions import deprecated - import reflex.state from reflex.base import Base from reflex.compiler.templates import STATEFUL_COMPONENT @@ -47,11 +45,10 @@ from reflex.event import ( EventChain, EventHandler, EventSpec, - EventVar, no_args_event_spec, ) from reflex.style import Style, format_as_emotion -from reflex.utils import console, format, imports, types +from reflex.utils import format, imports, types from reflex.utils.imports import ( ImmutableParsedImportDict, ImportDict, @@ -545,41 +542,6 @@ class Component(BaseComponent, ABC): # Construct the component. super().__init__(*args, **kwargs) - @deprecated("Use rx.EventChain.create instead.") - def _create_event_chain( - self, - args_spec: types.ArgsSpec | Sequence[types.ArgsSpec], - value: Union[ - Var, - EventHandler, - EventSpec, - List[Union[EventHandler, EventSpec, EventVar]], - Callable, - ], - key: Optional[str] = None, - ) -> Union[EventChain, Var]: - """Create an event chain from a variety of input types. - - Args: - args_spec: The args_spec of the event trigger being bound. - value: The value to create the event chain from. - key: The key of the event trigger being bound. - - Returns: - The event chain. - """ - console.deprecate( - "Component._create_event_chain", - "Use rx.EventChain.create instead.", - deprecation_version="0.6.8", - removal_version="0.7.0", - ) - return EventChain.create( - value=value, # type: ignore - args_spec=args_spec, - key=key, - ) - def get_event_triggers( self, ) -> Dict[str, types.ArgsSpec | Sequence[types.ArgsSpec]]: diff --git a/reflex/components/datadisplay/code.py b/reflex/components/datadisplay/code.py index 2d5dfc625..8b079745b 100644 --- a/reflex/components/datadisplay/code.py +++ b/reflex/components/datadisplay/code.py @@ -14,7 +14,7 @@ from reflex.components.radix.themes.layout.box import Box from reflex.constants.colors import Color from reflex.event import set_clipboard from reflex.style import Style -from reflex.utils import console, format +from reflex.utils import format from reflex.utils.imports import ImportVar from reflex.vars.base import LiteralVar, Var, VarData @@ -438,6 +438,8 @@ class CodeBlock(Component, MarkdownComponentMap): can_copy = props.pop("can_copy", False) copy_button = props.pop("copy_button", None) + # react-syntax-highlighter doesn't have an explicit "light" or "dark" theme so we use one-light and one-dark + # themes respectively to ensure code compatibility. if "theme" not in props: # Default color scheme responds to global color mode. props["theme"] = color_mode_cond( @@ -445,17 +447,6 @@ class CodeBlock(Component, MarkdownComponentMap): dark=Theme.one_dark, ) - # react-syntax-highlighter doesn't have an explicit "light" or "dark" theme so we use one-light and one-dark - # themes respectively to ensure code compatibility. - if "theme" in props and not isinstance(props["theme"], Var): - props["theme"] = getattr(Theme, format.to_snake_case(props["theme"])) # type: ignore - console.deprecate( - feature_name="theme prop as string", - reason="Use code_block.themes instead.", - deprecation_version="0.6.0", - removal_version="0.7.0", - ) - if can_copy: code = children[0] copy_button = ( # type: ignore diff --git a/reflex/event.py b/reflex/event.py index 0a4a01837..dbcf75d8e 100644 --- a/reflex/event.py +++ b/reflex/event.py @@ -40,7 +40,11 @@ from typing_extensions import ( from reflex import constants from reflex.constants.state import FRONTEND_EVENT_STATE from reflex.utils import console, format -from reflex.utils.exceptions import EventFnArgMismatch, EventHandlerArgTypeMismatch +from reflex.utils.exceptions import ( + EventFnArgMismatch, + EventHandlerArgTypeMismatch, + VarAnnotationError, +) from reflex.utils.types import ArgsSpec, GenericType, typehint_issubclass from reflex.vars import VarData from reflex.vars.base import LiteralVar, Var @@ -1272,11 +1276,12 @@ def call_event_handler( event_spec: The lambda that define the argument(s) to pass to the event handler. key: The key to pass to the event handler. + Raises: + EventHandlerArgTypeMismatch: If the event handler arguments do not match the event spec. + TypeError: If the event handler arguments are invalid. + Returns: The event spec from calling the event handler. - - # noqa: DAR401 failure - """ event_spec_args = parse_args_spec(event_spec) # type: ignore @@ -1315,8 +1320,6 @@ def call_event_handler( ) if event_spec_return_types: - failures = [] - event_callback_spec = inspect.getfullargspec(event_callback.fn) for event_spec_index, event_spec_return_type in enumerate( @@ -1344,25 +1347,17 @@ def call_event_handler( compare_result = typehint_issubclass( args_types_without_vars[i], type_hints_of_provided_callback[arg] ) - except TypeError: - # TODO: In 0.7.0, remove this block and raise the exception - # raise TypeError( - # f"Could not compare types {args_types_without_vars[i]} and {type_hints_of_provided_callback[arg]} for argument {arg} of {event_handler.fn.__qualname__} provided for {key}." # noqa: ERA001 - # ) from e - console.warn( + except TypeError as te: + raise TypeError( f"Could not compare types {args_types_without_vars[i]} and {type_hints_of_provided_callback[arg]} for argument {arg} of {event_callback.fn.__qualname__} provided for {key}." - ) - compare_result = False + ) from te if compare_result: continue else: - failure = EventHandlerArgTypeMismatch( + raise EventHandlerArgTypeMismatch( f"Event handler {key} expects {args_types_without_vars[i]} for argument {arg} but got {type_hints_of_provided_callback[arg]} as annotated in {event_callback.fn.__qualname__} instead." ) - failures.append(failure) - failed_type_check = True - break if not failed_type_check: if event_spec_index: @@ -1388,14 +1383,6 @@ def call_event_handler( ) return event_callback(*event_spec_args) - if failures: - console.deprecate( - "Mismatched event handler argument types", - "\n".join([str(f) for f in failures]), - "0.6.5", - "0.7.0", - ) - return event_callback(*event_spec_args) # type: ignore @@ -1420,19 +1407,15 @@ def resolve_annotation(annotations: dict[str, Any], arg_name: str): annotations: The annotations. arg_name: The argument name. + Raises: + VarAnnotationError: If the annotation is not found. + Returns: The resolved annotation. """ annotation = annotations.get(arg_name) if annotation is None: - console.deprecate( - feature_name="Unannotated event handler arguments", - reason="Provide type annotations for event handler arguments.", - deprecation_version="0.6.3", - removal_version="0.7.0", - ) - # Allow arbitrary attribute access two levels deep until removed. - return Dict[str, dict] + raise VarAnnotationError(arg_name, annotation) return annotation diff --git a/reflex/experimental/__init__.py b/reflex/experimental/__init__.py index 164790fe5..1a198f35a 100644 --- a/reflex/experimental/__init__.py +++ b/reflex/experimental/__init__.py @@ -9,7 +9,6 @@ from reflex.components.sonner.toast import toast as toast from ..utils.console import warn from . import hooks as hooks -from .assets import asset as asset from .client_state import ClientStateVar as ClientStateVar from .layout import layout as layout from .misc import run_in_thread as run_in_thread @@ -62,7 +61,6 @@ class ExperimentalNamespace(SimpleNamespace): _x = ExperimentalNamespace( - asset=asset, client_state=ClientStateVar.create, hooks=hooks, layout=layout, diff --git a/reflex/experimental/assets.py b/reflex/experimental/assets.py deleted file mode 100644 index e9be19aaf..000000000 --- a/reflex/experimental/assets.py +++ /dev/null @@ -1,37 +0,0 @@ -"""Helper functions for adding assets to the app.""" - -from typing import Optional - -from reflex import assets -from reflex.utils import console - - -def asset(relative_filename: str, subfolder: Optional[str] = None) -> str: - """DEPRECATED: use `rx.asset` with `shared=True` instead. - - Add an asset to the app. - Place the file next to your including python file. - Copies the file to the app's external assets directory. - - Example: - ```python - rx.script(src=rx._x.asset("my_custom_javascript.js")) - rx.image(src=rx._x.asset("test_image.png","subfolder")) - ``` - - Args: - relative_filename: The relative filename of the asset. - subfolder: The directory to place the asset in. - - Returns: - The relative URL to the copied asset. - """ - console.deprecate( - feature_name="rx._x.asset", - reason="Use `rx.asset` with `shared=True` instead of `rx._x.asset`.", - deprecation_version="0.6.6", - removal_version="0.7.0", - ) - return assets.asset( - relative_filename, shared=True, subfolder=subfolder, _stack_level=2 - ) diff --git a/reflex/state.py b/reflex/state.py index 1cd3e2c3e..2ed21c252 100644 --- a/reflex/state.py +++ b/reflex/state.py @@ -1772,7 +1772,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow): if ( isinstance(value, dict) and inspect.isclass(hinted_args) - and not types.is_generic_alias(hinted_args) # py3.9-py3.10 + and not types.is_generic_alias(hinted_args) # py3.10 ): if issubclass(hinted_args, Model): # Remove non-fields from the payload diff --git a/reflex/utils/exceptions.py b/reflex/utils/exceptions.py index ae5ec0168..b72c3fbf3 100644 --- a/reflex/utils/exceptions.py +++ b/reflex/utils/exceptions.py @@ -59,6 +59,21 @@ class VarAttributeError(ReflexError, AttributeError): """Custom AttributeError for var related errors.""" +class VarAnnotationError(ReflexError, TypeError): + """Custom AttributeError for var annotation related errors.""" + + def __init__(self, var_name, annotation_value): + """Initialize the VarAnnotationError. + + Args: + var_name: The name of the var. + annotation_value: The value of the annotation. + """ + super().__init__( + f"Invalid annotation '{annotation_value}' for var '{var_name}'." + ) + + class UploadValueError(ReflexError, ValueError): """Custom ValueError for upload related errors.""" diff --git a/reflex/utils/exec.py b/reflex/utils/exec.py index 621c4a608..0f6a80a0d 100644 --- a/reflex/utils/exec.py +++ b/reflex/utils/exec.py @@ -495,48 +495,3 @@ def is_prod_mode() -> bool: """ current_mode = environment.REFLEX_ENV_MODE.get() return current_mode == constants.Env.PROD - - -def is_frontend_only() -> bool: - """Check if the app is running in frontend-only mode. - - Returns: - True if the app is running in frontend-only mode. - """ - console.deprecate( - "is_frontend_only() is deprecated and will be removed in a future release.", - reason="Use `environment.REFLEX_FRONTEND_ONLY.get()` instead.", - deprecation_version="0.6.5", - removal_version="0.7.0", - ) - return environment.REFLEX_FRONTEND_ONLY.get() - - -def is_backend_only() -> bool: - """Check if the app is running in backend-only mode. - - Returns: - True if the app is running in backend-only mode. - """ - console.deprecate( - "is_backend_only() is deprecated and will be removed in a future release.", - reason="Use `environment.REFLEX_BACKEND_ONLY.get()` instead.", - deprecation_version="0.6.5", - removal_version="0.7.0", - ) - return environment.REFLEX_BACKEND_ONLY.get() - - -def should_skip_compile() -> bool: - """Whether the app should skip compile. - - Returns: - True if the app should skip compile. - """ - console.deprecate( - "should_skip_compile() is deprecated and will be removed in a future release.", - reason="Use `environment.REFLEX_SKIP_COMPILE.get()` instead.", - deprecation_version="0.6.5", - removal_version="0.7.0", - ) - return environment.REFLEX_SKIP_COMPILE.get() diff --git a/reflex/utils/format.py b/reflex/utils/format.py index 1d6671a0b..87d160553 100644 --- a/reflex/utils/format.py +++ b/reflex/utils/format.py @@ -11,7 +11,6 @@ from typing import TYPE_CHECKING, Any, List, Optional, Union from reflex import constants from reflex.constants.state import FRONTEND_EVENT_STATE from reflex.utils import exceptions -from reflex.utils.console import deprecate if TYPE_CHECKING: from reflex.components.component import ComponentStyle @@ -502,37 +501,6 @@ if TYPE_CHECKING: from reflex.vars import Var -def format_event_chain( - event_chain: EventChain | Var[EventChain], - event_arg: Var | None = None, -) -> str: - """DEPRECATED: format an event chain as a javascript invocation. - - Use str(rx.Var.create(event_chain)) instead. - - Args: - event_chain: The event chain to format. - event_arg: this argument is ignored. - - Returns: - Compiled javascript code to queue the given event chain on the frontend. - """ - deprecate( - feature_name="format_event_chain", - reason="Use str(rx.Var.create(event_chain)) instead", - deprecation_version="0.6.0", - removal_version="0.7.0", - ) - - from reflex.vars import Var - from reflex.vars.function import ArgsFunctionOperation - - result = Var.create(event_chain) - if isinstance(result, ArgsFunctionOperation): - result = result._return_expr - return str(result) - - def format_queue_events( events: EventType | None = None, args_spec: Optional[ArgsSpec] = None, diff --git a/reflex/utils/prerequisites.py b/reflex/utils/prerequisites.py index 797d28701..cfae83aa3 100644 --- a/reflex/utils/prerequisites.py +++ b/reflex/utils/prerequisites.py @@ -75,18 +75,6 @@ def get_web_dir() -> Path: return environment.REFLEX_WEB_WORKDIR.get() -def _python_version_check(): - """Emit deprecation warning for deprecated python versions.""" - # Check for end-of-life python versions. - if sys.version_info < (3, 10): - console.deprecate( - feature_name="Support for Python 3.9 and older", - reason="please upgrade to Python 3.10 or newer", - deprecation_version="0.6.0", - removal_version="0.7.0", - ) - - def check_latest_package_version(package_name: str): """Check if the latest version of the package is installed. @@ -109,8 +97,6 @@ def check_latest_package_version(package_name: str): console.warn( f"Your version ({current_version}) of {package_name} is out of date. Upgrade to {latest_version} with 'pip install {package_name} --upgrade'" ) - # Check for deprecated python versions - _python_version_check() except Exception: pass diff --git a/reflex/utils/telemetry.py b/reflex/utils/telemetry.py index fc90932a6..99bb6dd37 100644 --- a/reflex/utils/telemetry.py +++ b/reflex/utils/telemetry.py @@ -122,7 +122,7 @@ def _prepare_event(event: str, **kwargs) -> dict: return {} if UTC is None: - # for python 3.9 & 3.10 + # for python 3.10 stamp = datetime.utcnow().isoformat() else: # for python 3.11 & 3.12 diff --git a/reflex/vars/base.py b/reflex/vars/base.py index 094a478c8..1a5ddc9b0 100644 --- a/reflex/vars/base.py +++ b/reflex/vars/base.py @@ -541,38 +541,17 @@ class Var(Generic[VAR_TYPE]): def create( cls, value: Any, - _var_is_local: bool | None = None, - _var_is_string: bool | None = None, _var_data: VarData | None = None, ) -> Var: """Create a var from a value. Args: value: The value to create the var from. - _var_is_local: Whether the var is local. Deprecated. - _var_is_string: Whether the var is a string literal. Deprecated. _var_data: Additional hooks and imports associated with the Var. Returns: The var. """ - if _var_is_local is not None: - console.deprecate( - feature_name="_var_is_local", - reason="The _var_is_local argument is not supported for Var." - "If you want to create a Var from a raw Javascript expression, use the constructor directly", - deprecation_version="0.6.0", - removal_version="0.7.0", - ) - if _var_is_string is not None: - console.deprecate( - feature_name="_var_is_string", - reason="The _var_is_string argument is not supported for Var." - "If you want to create a Var from a raw Javascript expression, use the constructor directly", - deprecation_version="0.6.0", - removal_version="0.7.0", - ) - # If the value is already a var, do nothing. if isinstance(value, Var): return value @@ -581,12 +560,6 @@ class Var(Generic[VAR_TYPE]): if not isinstance(value, str): return LiteralVar.create(value) - if _var_is_string is False or _var_is_local is True: - return cls( - _js_expr=value, - _var_data=_var_data, - ) - return LiteralVar.create(value, _var_data=_var_data) @classmethod diff --git a/tests/integration/init-test/Dockerfile b/tests/integration/init-test/Dockerfile index f30466e7f..e5d2a0820 100644 --- a/tests/integration/init-test/Dockerfile +++ b/tests/integration/init-test/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.9 +FROM python:3.10 ARG USERNAME=kerrigan RUN useradd -m $USERNAME diff --git a/tests/units/assets/test_assets.py b/tests/units/assets/test_assets.py index b957f1902..dc444cfad 100644 --- a/tests/units/assets/test_assets.py +++ b/tests/units/assets/test_assets.py @@ -37,19 +37,6 @@ def test_shared_asset() -> None: assert not Path(Path.cwd() / "assets/external").exists() -def test_deprecated_x_asset(capsys) -> None: - """Test that the deprecated asset function raises a warning. - - Args: - capsys: Pytest fixture that captures stdout and stderr. - """ - assert rx.asset("custom_script.js", shared=True) == rx._x.asset("custom_script.js") - assert ( - "DeprecationWarning: rx._x.asset has been deprecated in version 0.6.6" - in capsys.readouterr().out - ) - - @pytest.mark.parametrize( "path,shared", [ diff --git a/tests/units/components/test_component.py b/tests/units/components/test_component.py index 674873b69..e8bd4ade4 100644 --- a/tests/units/components/test_component.py +++ b/tests/units/components/test_component.py @@ -27,7 +27,11 @@ from reflex.event import ( from reflex.state import BaseState from reflex.style import Style from reflex.utils import imports -from reflex.utils.exceptions import EventFnArgMismatch +from reflex.utils.exceptions import ( + EventFnArgMismatch, + EventHandlerArgTypeMismatch, + VarAnnotationError, +) from reflex.utils.imports import ImportDict, ImportVar, ParsedImportDict, parse_imports from reflex.vars import VarData from reflex.vars.base import LiteralVar, Var @@ -94,11 +98,14 @@ def component2() -> Type[Component]: A test component. """ + def on_prop_event_spec(e0: Any): + return [e0] + class TestComponent2(Component): # A test list prop. arr: Var[List[str]] - on_prop_event: EventHandler[lambda e0: [e0]] + on_prop_event: EventHandler[on_prop_event_spec] def get_event_triggers(self) -> Dict[str, Any]: """Test controlled triggers. @@ -842,13 +849,8 @@ def test_component_event_trigger_arbitrary_args(): "on_foo": on_foo_spec, } - comp = C1.create(on_foo=C1State.mock_handler) - - assert comp.render()["props"][0] == ( - "onFoo={((__e, _alpha, _bravo, _charlie) => (addEvents(" - f'[(Event("{C1State.get_full_name()}.mock_handler", ({{ ["_e"] : __e["target"]["value"], ["_bravo"] : _bravo["nested"], ["_charlie"] : (_charlie["custom"] + 42) }}), ({{ }})))], ' - "[__e, _alpha, _bravo, _charlie], ({ }))))}" - ) + with pytest.raises(VarAnnotationError): + C1.create(on_foo=C1State.mock_handler) def test_create_custom_component(my_component): @@ -914,21 +916,20 @@ def test_invalid_event_handler_args(component2, test_state): on_click=[test_state.do_something_arg, test_state.do_something] ) - # Enable when 0.7.0 happens # # Event Handler types must match - # with pytest.raises(EventHandlerArgTypeMismatch): - # component2.create( - # on_user_visited_count_changed=test_state.do_something_with_bool # noqa: ERA001 RUF100 - # ) # noqa: ERA001 RUF100 - # with pytest.raises(EventHandlerArgTypeMismatch): - # component2.create(on_user_list_changed=test_state.do_something_with_int) #noqa: ERA001 - # with pytest.raises(EventHandlerArgTypeMismatch): - # component2.create(on_user_list_changed=test_state.do_something_with_list_int) #noqa: ERA001 + with pytest.raises(EventHandlerArgTypeMismatch): + component2.create( + on_user_visited_count_changed=test_state.do_something_with_bool + ) + with pytest.raises(EventHandlerArgTypeMismatch): + component2.create(on_user_list_changed=test_state.do_something_with_int) + with pytest.raises(EventHandlerArgTypeMismatch): + component2.create(on_user_list_changed=test_state.do_something_with_list_int) - # component2.create(on_open=test_state.do_something_with_int) #noqa: ERA001 - # component2.create(on_open=test_state.do_something_with_bool) #noqa: ERA001 - # component2.create(on_user_visited_count_changed=test_state.do_something_with_int) #noqa: ERA001 - # component2.create(on_user_list_changed=test_state.do_something_with_list_str) #noqa: ERA001 + component2.create(on_open=test_state.do_something_with_int) + component2.create(on_open=test_state.do_something_with_bool) + component2.create(on_user_visited_count_changed=test_state.do_something_with_int) + component2.create(on_user_list_changed=test_state.do_something_with_list_str) # lambda cannot return weird values. with pytest.raises(ValueError): @@ -1798,21 +1799,15 @@ def test_custom_component_declare_event_handlers_in_fields(): """ return { **super().get_event_triggers(), - "on_a": lambda e0: [e0], "on_b": input_event, - "on_c": lambda e0: [], "on_d": lambda: [], "on_e": lambda: [], - "on_f": lambda a, b, c: [c, b, a], } class TestComponent(Component): - on_a: EventHandler[lambda e0: [e0]] on_b: EventHandler[input_event] - on_c: EventHandler[no_args_event_spec] on_d: EventHandler[no_args_event_spec] on_e: EventHandler - on_f: EventHandler[lambda a, b, c: [c, b, a]] custom_component = ReferenceComponent.create() test_component = TestComponent.create()