remove deprecated features and support for py3.9

This commit is contained in:
Lendemor 2025-01-03 17:17:32 +01:00
parent 12eaf08c88
commit 7cc78cd8ce
36 changed files with 85 additions and 338 deletions

View File

@ -81,15 +81,11 @@ jobs:
matrix: matrix:
# Show OS combos first in GUI # Show OS combos first in GUI
os: [ubuntu-latest, windows-latest, macos-latest] 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: exclude:
- os: windows-latest - os: windows-latest
python-version: '3.10.13' python-version: '3.10.13'
- os: windows-latest
python-version: '3.9.18'
# keep only one python version for MacOS # keep only one python version for MacOS
- os: macos-latest
python-version: '3.9.18'
- os: macos-latest - os: macos-latest
python-version: '3.10.13' python-version: '3.10.13'
- os: macos-latest - os: macos-latest
@ -97,8 +93,6 @@ jobs:
include: include:
- os: windows-latest - os: windows-latest
python-version: '3.10.11' python-version: '3.10.11'
- os: windows-latest
python-version: '3.9.13'
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:

View File

@ -16,7 +16,7 @@ jobs:
- uses: ./.github/actions/setup_build_env - uses: ./.github/actions/setup_build_env
with: with:
python-version: '3.9' python-version: '3.10'
run-poetry-install: true run-poetry-install: true
create-venv-at-path: .venv create-venv-at-path: .venv

View File

@ -43,17 +43,13 @@ jobs:
matrix: matrix:
# Show OS combos first in GUI # Show OS combos first in GUI
os: [ubuntu-latest, windows-latest] 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: exclude:
- os: windows-latest - os: windows-latest
python-version: '3.10.13' python-version: '3.10.13'
- os: windows-latest
python-version: '3.9.18'
include: include:
- os: windows-latest - os: windows-latest
python-version: '3.10.11' python-version: '3.10.11'
- os: windows-latest
python-version: '3.9.13'
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:

View File

@ -28,18 +28,14 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
os: [ubuntu-latest, windows-latest] 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 # Windows is a bit behind on Python version availability in Github
exclude: exclude:
- os: windows-latest - os: windows-latest
python-version: '3.10.13' python-version: '3.10.13'
- os: windows-latest
python-version: '3.9.18'
include: include:
- os: windows-latest - os: windows-latest
python-version: '3.10.11' python-version: '3.10.11'
- os: windows-latest
python-version: '3.9.13'
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
# Service containers to run with `runner-job` # Service containers to run with `runner-job`
@ -88,8 +84,8 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
# Note: py39, py310 versions chosen due to available arm64 darwin builds. # Note: py310 version chosen due to available arm64 darwin builds.
python-version: ['3.9.13', '3.10.11', '3.11.5', '3.12.0', '3.13.0'] python-version: ['3.10.11', '3.11.5', '3.12.0', '3.13.0']
runs-on: macos-latest runs-on: macos-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4

View File

@ -8,7 +8,7 @@ Here is a quick guide on how to run Reflex repo locally so you can start contrib
**Prerequisites:** **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). - 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:** **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. 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 ``` bash
pre-commit install pre-commit install

View File

@ -34,7 +34,7 @@ See our [architecture page](https://reflex.dev/blog/2024-03-21-reflex-architectu
## ⚙️ Installation ## ⚙️ Installation
Open a terminal and run (Requires Python 3.9+): Open a terminal and run (Requires Python 3.10+):
```bash ```bash
pip install reflex pip install reflex

View File

@ -34,7 +34,7 @@ Auf unserer [Architektur-Seite](https://reflex.dev/blog/2024-03-21-reflex-archit
## ⚙️ Installation ## ⚙️ 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 ```bash
pip install reflex pip install reflex

View File

@ -35,7 +35,7 @@ Consulta nuestra [página de arquitectura](https://reflex.dev/blog/2024-03-21-re
## ⚙️ Instalación ## ⚙️ Instalación
Abra un terminal y ejecute (Requiere Python 3.9+): Abra un terminal y ejecute (Requiere Python 3.10+):
```bash ```bash
pip install reflex pip install reflex

View File

@ -35,7 +35,7 @@ Reflex के अंदर के कामकाज को जानने क
## ⚙️ इंस्टॉलेशन (Installation) ## ⚙️ इंस्टॉलेशन (Installation)
एक टर्मिनल खोलें और चलाएं (Python 3.9+ की आवश्यकता है): एक टर्मिनल खोलें और चलाएं (Python 3.10+ की आवश्यकता है):
```bash ```bash
pip install reflex pip install reflex

View File

@ -22,7 +22,7 @@
## ⚙️ Installazione ## ⚙️ Installazione
Apri un terminale ed esegui (Richiede Python 3.9+): Apri un terminale ed esegui (Richiede Python 3.10+):
```bash ```bash
pip install reflex pip install reflex

View File

@ -37,7 +37,7 @@ Reflex がどのように動作しているかを知るには、[アーキテク
## ⚙️ インストール ## ⚙️ インストール
ターミナルを開いて以下のコマンドを実行してください。Python 3.9 以上が必要です。): ターミナルを開いて以下のコマンドを実行してください。Python 3.10 以上が必要です。):
```bash ```bash
pip install reflex pip install reflex

View File

@ -20,7 +20,7 @@
--- ---
## ⚙️ 설치 ## ⚙️ 설치
터미널을 열고 실행하세요. (Python 3.9+ 필요): 터미널을 열고 실행하세요. (Python 3.10+ 필요):
```bash ```bash
pip install reflex pip install reflex

View File

@ -34,7 +34,7 @@
## ⚙️ Installation - نصب و راه اندازی ## ⚙️ Installation - نصب و راه اندازی
یک ترمینال را باز کنید و اجرا کنید (نیازمند Python 3.9+): یک ترمینال را باز کنید و اجرا کنید (نیازمند Python 3.10+):
```bash ```bash
pip install reflex pip install reflex

View File

@ -21,7 +21,7 @@
--- ---
## ⚙️ Instalação ## ⚙️ Instalação
Abra um terminal e execute (Requer Python 3.9+): Abra um terminal e execute (Requer Python 3.10+):
```bash ```bash
pip install reflex pip install reflex

View File

@ -24,7 +24,7 @@
## ⚙️ Kurulum ## ⚙️ 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 ```bash
pip install reflex pip install reflex

View File

@ -34,7 +34,7 @@ Các tính năng chính:
## ⚙️ Cài đặt ## ⚙️ 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 ```bash
pip install reflex pip install reflex

View File

@ -34,7 +34,7 @@ Reflex 是一个使用纯Python构建全栈web应用的库。
## ⚙️ 安装 ## ⚙️ 安装
打开一个终端并且运行(要求Python3.9+): 打开一个终端并且运行(要求Python3.10+):
```bash ```bash
pip install reflex pip install reflex

View File

@ -36,7 +36,7 @@ Reflex 是一個可以用純 Python 構建全端網頁應用程式的函式庫
## ⚙️ 安裝 ## ⚙️ 安裝
開啟一個終端機並且執行 (需要 Python 3.9+): 開啟一個終端機並且執行 (需要 Python 3.10+):
```bash ```bash
pip install reflex pip install reflex

View File

@ -19,7 +19,7 @@ classifiers = ["Development Status :: 4 - Beta"]
packages = [{ include = "reflex" }] packages = [{ include = "reflex" }]
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = "^3.9" python = "^3.10"
fastapi = ">=0.96.0,!=0.111.0,!=0.111.1" fastapi = ">=0.96.0,!=0.111.0,!=0.111.1"
gunicorn = ">=20.1.0,<24.0" gunicorn = ">=20.1.0,<24.0"
jinja2 = ">=3.1.2,<4.0" jinja2 = ">=3.1.2,<4.0"

View File

@ -8,7 +8,7 @@ version = "0.0.1"
description = "Reflex custom component {{ module_name }}" description = "Reflex custom component {{ module_name }}"
readme = "README.md" readme = "README.md"
license = { text = "Apache-2.0" } license = { text = "Apache-2.0" }
requires-python = ">=3.9" requires-python = ">=3.10"
authors = [{ name = "", email = "YOUREMAIL@domain.com" }] authors = [{ name = "", email = "YOUREMAIL@domain.com" }]
keywords = ["reflex","reflex-custom-components"] keywords = ["reflex","reflex-custom-components"]

View File

@ -367,19 +367,4 @@ getattr, __dir__, __all__ = lazy_loader.attach(
def __getattr__(name): 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) return getattr(name)

View File

@ -23,8 +23,6 @@ from typing import (
Union, Union,
) )
from typing_extensions import deprecated
import reflex.state import reflex.state
from reflex.base import Base from reflex.base import Base
from reflex.compiler.templates import STATEFUL_COMPONENT from reflex.compiler.templates import STATEFUL_COMPONENT
@ -47,11 +45,10 @@ from reflex.event import (
EventChain, EventChain,
EventHandler, EventHandler,
EventSpec, EventSpec,
EventVar,
no_args_event_spec, no_args_event_spec,
) )
from reflex.style import Style, format_as_emotion 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 ( from reflex.utils.imports import (
ImmutableParsedImportDict, ImmutableParsedImportDict,
ImportDict, ImportDict,
@ -545,41 +542,6 @@ class Component(BaseComponent, ABC):
# Construct the component. # Construct the component.
super().__init__(*args, **kwargs) 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( def get_event_triggers(
self, self,
) -> Dict[str, types.ArgsSpec | Sequence[types.ArgsSpec]]: ) -> Dict[str, types.ArgsSpec | Sequence[types.ArgsSpec]]:

View File

@ -14,7 +14,7 @@ from reflex.components.radix.themes.layout.box import Box
from reflex.constants.colors import Color from reflex.constants.colors import Color
from reflex.event import set_clipboard from reflex.event import set_clipboard
from reflex.style import Style from reflex.style import Style
from reflex.utils import console, format from reflex.utils import format
from reflex.utils.imports import ImportVar from reflex.utils.imports import ImportVar
from reflex.vars.base import LiteralVar, Var, VarData from reflex.vars.base import LiteralVar, Var, VarData
@ -438,6 +438,8 @@ class CodeBlock(Component, MarkdownComponentMap):
can_copy = props.pop("can_copy", False) can_copy = props.pop("can_copy", False)
copy_button = props.pop("copy_button", None) 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: if "theme" not in props:
# Default color scheme responds to global color mode. # Default color scheme responds to global color mode.
props["theme"] = color_mode_cond( props["theme"] = color_mode_cond(
@ -445,17 +447,6 @@ class CodeBlock(Component, MarkdownComponentMap):
dark=Theme.one_dark, 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: if can_copy:
code = children[0] code = children[0]
copy_button = ( # type: ignore copy_button = ( # type: ignore

View File

@ -40,7 +40,11 @@ from typing_extensions import (
from reflex import constants from reflex import constants
from reflex.constants.state import FRONTEND_EVENT_STATE from reflex.constants.state import FRONTEND_EVENT_STATE
from reflex.utils import console, format 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.utils.types import ArgsSpec, GenericType, typehint_issubclass
from reflex.vars import VarData from reflex.vars import VarData
from reflex.vars.base import LiteralVar, Var 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. event_spec: The lambda that define the argument(s) to pass to the event handler.
key: The key 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: Returns:
The event spec from calling the event handler. The event spec from calling the event handler.
# noqa: DAR401 failure
""" """
event_spec_args = parse_args_spec(event_spec) # type: ignore event_spec_args = parse_args_spec(event_spec) # type: ignore
@ -1315,8 +1320,6 @@ def call_event_handler(
) )
if event_spec_return_types: if event_spec_return_types:
failures = []
event_callback_spec = inspect.getfullargspec(event_callback.fn) event_callback_spec = inspect.getfullargspec(event_callback.fn)
for event_spec_index, event_spec_return_type in enumerate( for event_spec_index, event_spec_return_type in enumerate(
@ -1344,25 +1347,17 @@ def call_event_handler(
compare_result = typehint_issubclass( compare_result = typehint_issubclass(
args_types_without_vars[i], type_hints_of_provided_callback[arg] args_types_without_vars[i], type_hints_of_provided_callback[arg]
) )
except TypeError: except TypeError as te:
# TODO: In 0.7.0, remove this block and raise the exception raise TypeError(
# 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(
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}." 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}."
) ) from te
compare_result = False
if compare_result: if compare_result:
continue continue
else: 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." 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 not failed_type_check:
if event_spec_index: if event_spec_index:
@ -1388,14 +1383,6 @@ def call_event_handler(
) )
return event_callback(*event_spec_args) 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 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. annotations: The annotations.
arg_name: The argument name. arg_name: The argument name.
Raises:
VarAnnotationError: If the annotation is not found.
Returns: Returns:
The resolved annotation. The resolved annotation.
""" """
annotation = annotations.get(arg_name) annotation = annotations.get(arg_name)
if annotation is None: if annotation is None:
console.deprecate( raise VarAnnotationError(arg_name, annotation)
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]
return annotation return annotation

View File

@ -9,7 +9,6 @@ from reflex.components.sonner.toast import toast as toast
from ..utils.console import warn from ..utils.console import warn
from . import hooks as hooks from . import hooks as hooks
from .assets import asset as asset
from .client_state import ClientStateVar as ClientStateVar from .client_state import ClientStateVar as ClientStateVar
from .layout import layout as layout from .layout import layout as layout
from .misc import run_in_thread as run_in_thread from .misc import run_in_thread as run_in_thread
@ -62,7 +61,6 @@ class ExperimentalNamespace(SimpleNamespace):
_x = ExperimentalNamespace( _x = ExperimentalNamespace(
asset=asset,
client_state=ClientStateVar.create, client_state=ClientStateVar.create,
hooks=hooks, hooks=hooks,
layout=layout, layout=layout,

View File

@ -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
)

View File

@ -1772,7 +1772,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
if ( if (
isinstance(value, dict) isinstance(value, dict)
and inspect.isclass(hinted_args) 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): if issubclass(hinted_args, Model):
# Remove non-fields from the payload # Remove non-fields from the payload

View File

@ -59,6 +59,21 @@ class VarAttributeError(ReflexError, AttributeError):
"""Custom AttributeError for var related errors.""" """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): class UploadValueError(ReflexError, ValueError):
"""Custom ValueError for upload related errors.""" """Custom ValueError for upload related errors."""

View File

@ -495,48 +495,3 @@ def is_prod_mode() -> bool:
""" """
current_mode = environment.REFLEX_ENV_MODE.get() current_mode = environment.REFLEX_ENV_MODE.get()
return current_mode == constants.Env.PROD 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()

View File

@ -11,7 +11,6 @@ from typing import TYPE_CHECKING, Any, List, Optional, Union
from reflex import constants from reflex import constants
from reflex.constants.state import FRONTEND_EVENT_STATE from reflex.constants.state import FRONTEND_EVENT_STATE
from reflex.utils import exceptions from reflex.utils import exceptions
from reflex.utils.console import deprecate
if TYPE_CHECKING: if TYPE_CHECKING:
from reflex.components.component import ComponentStyle from reflex.components.component import ComponentStyle
@ -502,37 +501,6 @@ if TYPE_CHECKING:
from reflex.vars import Var 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( def format_queue_events(
events: EventType | None = None, events: EventType | None = None,
args_spec: Optional[ArgsSpec] = None, args_spec: Optional[ArgsSpec] = None,

View File

@ -75,18 +75,6 @@ def get_web_dir() -> Path:
return environment.REFLEX_WEB_WORKDIR.get() 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): def check_latest_package_version(package_name: str):
"""Check if the latest version of the package is installed. """Check if the latest version of the package is installed.
@ -109,8 +97,6 @@ def check_latest_package_version(package_name: str):
console.warn( console.warn(
f"Your version ({current_version}) of {package_name} is out of date. Upgrade to {latest_version} with 'pip install {package_name} --upgrade'" 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: except Exception:
pass pass

View File

@ -122,7 +122,7 @@ def _prepare_event(event: str, **kwargs) -> dict:
return {} return {}
if UTC is None: if UTC is None:
# for python 3.9 & 3.10 # for python 3.10
stamp = datetime.utcnow().isoformat() stamp = datetime.utcnow().isoformat()
else: else:
# for python 3.11 & 3.12 # for python 3.11 & 3.12

View File

@ -541,38 +541,17 @@ class Var(Generic[VAR_TYPE]):
def create( def create(
cls, cls,
value: Any, value: Any,
_var_is_local: bool | None = None,
_var_is_string: bool | None = None,
_var_data: VarData | None = None, _var_data: VarData | None = None,
) -> Var: ) -> Var:
"""Create a var from a value. """Create a var from a value.
Args: Args:
value: The value to create the var from. 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. _var_data: Additional hooks and imports associated with the Var.
Returns: Returns:
The var. 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 the value is already a var, do nothing.
if isinstance(value, Var): if isinstance(value, Var):
return value return value
@ -581,12 +560,6 @@ class Var(Generic[VAR_TYPE]):
if not isinstance(value, str): if not isinstance(value, str):
return LiteralVar.create(value) 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) return LiteralVar.create(value, _var_data=_var_data)
@classmethod @classmethod

View File

@ -1,4 +1,4 @@
FROM python:3.9 FROM python:3.10
ARG USERNAME=kerrigan ARG USERNAME=kerrigan
RUN useradd -m $USERNAME RUN useradd -m $USERNAME

View File

@ -37,19 +37,6 @@ def test_shared_asset() -> None:
assert not Path(Path.cwd() / "assets/external").exists() 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( @pytest.mark.parametrize(
"path,shared", "path,shared",
[ [

View File

@ -27,7 +27,11 @@ from reflex.event import (
from reflex.state import BaseState from reflex.state import BaseState
from reflex.style import Style from reflex.style import Style
from reflex.utils import imports 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.utils.imports import ImportDict, ImportVar, ParsedImportDict, parse_imports
from reflex.vars import VarData from reflex.vars import VarData
from reflex.vars.base import LiteralVar, Var from reflex.vars.base import LiteralVar, Var
@ -94,11 +98,14 @@ def component2() -> Type[Component]:
A test component. A test component.
""" """
def on_prop_event_spec(e0: Any):
return [e0]
class TestComponent2(Component): class TestComponent2(Component):
# A test list prop. # A test list prop.
arr: Var[List[str]] 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]: def get_event_triggers(self) -> Dict[str, Any]:
"""Test controlled triggers. """Test controlled triggers.
@ -842,13 +849,8 @@ def test_component_event_trigger_arbitrary_args():
"on_foo": on_foo_spec, "on_foo": on_foo_spec,
} }
comp = C1.create(on_foo=C1State.mock_handler) with pytest.raises(VarAnnotationError):
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], ({ }))))}"
)
def test_create_custom_component(my_component): 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] on_click=[test_state.do_something_arg, test_state.do_something]
) )
# Enable when 0.7.0 happens
# # Event Handler types must match # # Event Handler types must match
# with pytest.raises(EventHandlerArgTypeMismatch): with pytest.raises(EventHandlerArgTypeMismatch):
# component2.create( component2.create(
# on_user_visited_count_changed=test_state.do_something_with_bool # noqa: ERA001 RUF100 on_user_visited_count_changed=test_state.do_something_with_bool
# ) # noqa: ERA001 RUF100 )
# with pytest.raises(EventHandlerArgTypeMismatch): with pytest.raises(EventHandlerArgTypeMismatch):
# component2.create(on_user_list_changed=test_state.do_something_with_int) #noqa: ERA001 component2.create(on_user_list_changed=test_state.do_something_with_int)
# with pytest.raises(EventHandlerArgTypeMismatch): with pytest.raises(EventHandlerArgTypeMismatch):
# component2.create(on_user_list_changed=test_state.do_something_with_list_int) #noqa: ERA001 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_int)
# component2.create(on_open=test_state.do_something_with_bool) #noqa: ERA001 component2.create(on_open=test_state.do_something_with_bool)
# component2.create(on_user_visited_count_changed=test_state.do_something_with_int) #noqa: ERA001 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) #noqa: ERA001 component2.create(on_user_list_changed=test_state.do_something_with_list_str)
# lambda cannot return weird values. # lambda cannot return weird values.
with pytest.raises(ValueError): with pytest.raises(ValueError):
@ -1798,21 +1799,15 @@ def test_custom_component_declare_event_handlers_in_fields():
""" """
return { return {
**super().get_event_triggers(), **super().get_event_triggers(),
"on_a": lambda e0: [e0],
"on_b": input_event, "on_b": input_event,
"on_c": lambda e0: [],
"on_d": lambda: [], "on_d": lambda: [],
"on_e": lambda: [], "on_e": lambda: [],
"on_f": lambda a, b, c: [c, b, a],
} }
class TestComponent(Component): class TestComponent(Component):
on_a: EventHandler[lambda e0: [e0]]
on_b: EventHandler[input_event] on_b: EventHandler[input_event]
on_c: EventHandler[no_args_event_spec]
on_d: EventHandler[no_args_event_spec] on_d: EventHandler[no_args_event_spec]
on_e: EventHandler on_e: EventHandler
on_f: EventHandler[lambda a, b, c: [c, b, a]]
custom_component = ReferenceComponent.create() custom_component = ReferenceComponent.create()
test_component = TestComponent.create() test_component = TestComponent.create()