浏览代码

removing deprecated features for 0.7.0 and removing py3.9 support (#4586)

* remove deprecated features and support for py3.9

* remove other deprecated stuff

* update lock file

* fix units tests

* relock poetry

* fix _replace for computed_var

* fix some merge typo

* fix typing of deploy args

* fix benchmarks.yml versions

* console.error instead of raising Exception

* fix tests

* ignore lambdas when resolving annotations

* simplify redirect logic in event.py

* more fixes

* fix unit tests again

* give back default annotations for lambdas

* fix signature check for on_submit

* remove useless stuff

* update pyi

* readd the getattr

* raise if log_level is wrong type

* silly goose, loglevel is a subclass of str

* i don't believe this code

* add guard

---------

Co-authored-by: Khaleel Al-Adhami <khaleel.aladhami@gmail.com>
Thomas Brandého 3 月之前
父节点
当前提交
4c2b2ed1c6
共有 52 个文件被更改,包括 703 次插入1044 次删除
  1. 4 10
      .github/workflows/benchmarks.yml
  2. 1 1
      .github/workflows/check_outdated_dependencies.yml
  3. 3 8
      .github/workflows/integration_tests.yml
  4. 3 7
      .github/workflows/unit_tests.yml
  5. 1 1
      .pre-commit-config.yaml
  6. 2 2
      CONTRIBUTING.md
  7. 1 1
      README.md
  8. 1 1
      docs/de/README.md
  9. 1 1
      docs/es/README.md
  10. 1 1
      docs/in/README.md
  11. 1 1
      docs/it/README.md
  12. 1 1
      docs/ja/README.md
  13. 1 1
      docs/kr/README.md
  14. 1 1
      docs/pe/README.md
  15. 1 1
      docs/pt/pt_br/README.md
  16. 1 1
      docs/tr/README.md
  17. 1 1
      docs/vi/README.md
  18. 1 1
      docs/zh/zh_cn/README.md
  19. 1 1
      docs/zh/zh_tw/README.md
  20. 399 467
      poetry.lock
  21. 2 3
      pyproject.toml
  22. 1 1
      reflex/.templates/jinja/custom_components/pyproject.toml.jinja2
  23. 0 16
      reflex/__init__.py
  24. 0 1
      reflex/__init__.pyi
  25. 1 39
      reflex/components/component.py
  26. 3 12
      reflex/components/datadisplay/code.py
  27. 2 2
      reflex/components/el/elements/forms.py
  28. 4 4
      reflex/components/el/elements/forms.pyi
  29. 6 6
      reflex/components/radix/primitives/form.pyi
  30. 64 114
      reflex/event.py
  31. 0 2
      reflex/experimental/__init__.py
  32. 0 37
      reflex/experimental/assets.py
  33. 19 6
      reflex/reflex.py
  34. 4 7
      reflex/state.py
  35. 3 1
      reflex/style.py
  36. 3 11
      reflex/utils/console.py
  37. 42 20
      reflex/utils/exceptions.py
  38. 12 54
      reflex/utils/exec.py
  39. 0 32
      reflex/utils/format.py
  40. 7 17
      reflex/utils/prerequisites.py
  41. 1 1
      reflex/utils/telemetry.py
  42. 7 44
      reflex/vars/base.py
  43. 1 1
      tests/integration/init-test/Dockerfile
  44. 25 23
      tests/integration/test_call_script.py
  45. 6 6
      tests/integration/test_client_storage.py
  46. 0 13
      tests/units/assets/test_assets.py
  47. 6 8
      tests/units/components/datadisplay/conftest.py
  48. 5 4
      tests/units/components/datadisplay/test_datatable.py
  49. 40 39
      tests/units/components/test_component.py
  50. 3 4
      tests/units/test_event.py
  51. 5 5
      tests/units/test_state.py
  52. 5 2
      tests/units/test_var.py

+ 4 - 10
.github/workflows/benchmarks.yml

@@ -81,24 +81,18 @@ 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.21", "3.10.16", "3.11.11", "3.12.8"]
+        python-version: ['3.10.16', '3.11.11', '3.12.8']
         exclude:
         exclude:
           - os: windows-latest
           - os: windows-latest
-            python-version: "3.10.16"
-          - os: windows-latest
-            python-version: "3.9.21"
+            python-version: '3.10.16'
           # keep only one python version for MacOS
           # keep only one python version for MacOS
           - os: macos-latest
           - os: macos-latest
-            python-version: "3.9.21"
-          - os: macos-latest
-            python-version: "3.10.16"
+            python-version: '3.10.16'
           - os: macos-latest
           - os: macos-latest
             python-version: "3.11.11"
             python-version: "3.11.11"
         include:
         include:
           - os: windows-latest
           - os: windows-latest
-            python-version: "3.10.11"
-          - os: windows-latest
-            python-version: "3.9.13"
+            python-version: '3.10.11'
 
 
     runs-on: ${{ matrix.os }}
     runs-on: ${{ matrix.os }}
     steps:
     steps:

+ 1 - 1
.github/workflows/check_outdated_dependencies.yml

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

+ 3 - 8
.github/workflows/integration_tests.yml

@@ -43,22 +43,17 @@ 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.21", "3.10.16", "3.11.11", "3.12.8", "3.13.1"]
-        # Windows is a bit behind on Python version availability in Github
+        python-version: ['3.10.16', '3.11.11', '3.12.8', '3.13.1']
         exclude:
         exclude:
           - os: windows-latest
           - os: windows-latest
             python-version: "3.11.11"
             python-version: "3.11.11"
           - os: windows-latest
           - os: windows-latest
-            python-version: "3.10.16"
-          - os: windows-latest
-            python-version: "3.9.21"
+            python-version: '3.10.16'
         include:
         include:
           - os: windows-latest
           - os: windows-latest
             python-version: "3.11.9"
             python-version: "3.11.9"
           - os: windows-latest
           - os: windows-latest
-            python-version: "3.10.11"
-          - os: windows-latest
-            python-version: "3.9.13"
+            python-version: '3.10.11'
 
 
     runs-on: ${{ matrix.os }}
     runs-on: ${{ matrix.os }}
     steps:
     steps:

+ 3 - 7
.github/workflows/unit_tests.yml

@@ -28,22 +28,18 @@ jobs:
       fail-fast: false
       fail-fast: false
       matrix:
       matrix:
         os: [ubuntu-latest, windows-latest]
         os: [ubuntu-latest, windows-latest]
-        python-version: ["3.9.21", "3.10.16", "3.11.11", "3.12.8", "3.13.1"]
+        python-version: ["3.10.16", "3.11.11", "3.12.8", "3.13.1"]
         # 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.11.11"
             python-version: "3.11.11"
           - os: windows-latest
           - os: windows-latest
             python-version: "3.10.16"
             python-version: "3.10.16"
-          - os: windows-latest
-            python-version: "3.9.21"
         include:
         include:
           - os: windows-latest
           - os: windows-latest
             python-version: "3.11.9"
             python-version: "3.11.9"
           - 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`
@@ -92,8 +88,8 @@ jobs:
     strategy:
     strategy:
       fail-fast: false
       fail-fast: false
       matrix:
       matrix:
-        # Note: py39, py310, py311 versions chosen due to available arm64 darwin builds.
-        python-version: ["3.9.13", "3.10.11", "3.11.9", "3.12.8", "3.13.1"]
+        # Note: py310, py311 versions chosen due to available arm64 darwin builds.
+        python-version: ["3.10.11", "3.11.9", "3.12.8", "3.13.1"]
     runs-on: macos-latest
     runs-on: macos-latest
     steps:
     steps:
       - uses: actions/checkout@v4
       - uses: actions/checkout@v4

+ 1 - 1
.pre-commit-config.yaml

@@ -28,7 +28,7 @@ repos:
         entry: python3 scripts/make_pyi.py
         entry: python3 scripts/make_pyi.py
 
 
   - repo: https://github.com/RobertCraigie/pyright-python
   - repo: https://github.com/RobertCraigie/pyright-python
-    rev: v1.1.313
+    rev: v1.1.334
     hooks:
     hooks:
       - id: pyright
       - id: pyright
         args: [reflex, tests]
         args: [reflex, tests]

+ 2 - 2
CONTRIBUTING.md

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

+ 1 - 1
README.md

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

+ 1 - 1
docs/de/README.md

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

+ 1 - 1
docs/es/README.md

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

+ 1 - 1
docs/in/README.md

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

+ 1 - 1
docs/it/README.md

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

+ 1 - 1
docs/ja/README.md

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

+ 1 - 1
docs/kr/README.md

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

+ 1 - 1
docs/pe/README.md

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

+ 1 - 1
docs/pt/pt_br/README.md

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

+ 1 - 1
docs/tr/README.md

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

+ 1 - 1
docs/vi/README.md

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

+ 1 - 1
docs/zh/zh_cn/README.md

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

+ 1 - 1
docs/zh/zh_tw/README.md

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

文件差异内容过多而无法显示
+ 399 - 467
poetry.lock


+ 2 - 3
pyproject.toml

@@ -18,7 +18,7 @@ keywords = ["web", "framework"]
 classifiers = ["Development Status :: 4 - Beta"]
 classifiers = ["Development Status :: 4 - Beta"]
 
 
 [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"
@@ -50,7 +50,6 @@ httpx = ">=0.25.1,<1.0"
 twine = ">=4.0.0,<7.0"
 twine = ">=4.0.0,<7.0"
 tomlkit = ">=0.12.4,<1.0"
 tomlkit = ">=0.12.4,<1.0"
 lazy_loader = ">=0.4"
 lazy_loader = ">=0.4"
-reflex-chakra = ">=0.6.0"
 typing_extensions = ">=4.6.0"
 typing_extensions = ">=4.6.0"
 
 
 [tool.poetry.group.dev.dependencies]
 [tool.poetry.group.dev.dependencies]
@@ -102,5 +101,5 @@ asyncio_default_fixture_loop_scope = "function"
 asyncio_mode = "auto"
 asyncio_mode = "auto"
 
 
 [tool.codespell]
 [tool.codespell]
-skip = "docs/*,*.html,examples/*, *.pyi"
+skip = "docs/*,*.html,examples/*, *.pyi, poetry.lock"
 ignore-words-list = "te, TreeE"
 ignore-words-list = "te, TreeE"

+ 1 - 1
reflex/.templates/jinja/custom_components/pyproject.toml.jinja2

@@ -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"]
 
 

+ 0 - 16
reflex/__init__.py

@@ -303,7 +303,6 @@ _MAPPING: dict = {
     "event": [
     "event": [
         "EventChain",
         "EventChain",
         "EventHandler",
         "EventHandler",
-        "background",
         "call_script",
         "call_script",
         "call_function",
         "call_function",
         "run_script",
         "run_script",
@@ -367,19 +366,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)

+ 0 - 1
reflex/__init__.pyi

@@ -156,7 +156,6 @@ from .constants import Env as Env
 from .constants.colors import Color as Color
 from .constants.colors import Color as Color
 from .event import EventChain as EventChain
 from .event import EventChain as EventChain
 from .event import EventHandler as EventHandler
 from .event import EventHandler as EventHandler
-from .event import background as background
 from .event import call_function as call_function
 from .event import call_function as call_function
 from .event import call_script as call_script
 from .event import call_script as call_script
 from .event import clear_local_storage as clear_local_storage
 from .event import clear_local_storage as clear_local_storage

+ 1 - 39
reflex/components/component.py

@@ -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,
@@ -547,41 +544,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]]:

+ 3 - 12
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.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

+ 2 - 2
reflex/components/el/elements/forms.py

@@ -102,7 +102,7 @@ class Fieldset(Element):
     name: Var[Union[str, int, bool]]
     name: Var[Union[str, int, bool]]
 
 
 
 
-def on_submit_event_spec() -> Tuple[Var[Dict[str, Any]]]:
+def on_submit_event_spec() -> Tuple[Var[dict[str, Any]]]:
     """Event handler spec for the on_submit event.
     """Event handler spec for the on_submit event.
 
 
     Returns:
     Returns:
@@ -111,7 +111,7 @@ def on_submit_event_spec() -> Tuple[Var[Dict[str, Any]]]:
     return (FORM_DATA,)
     return (FORM_DATA,)
 
 
 
 
-def on_submit_string_event_spec() -> Tuple[Var[Dict[str, str]]]:
+def on_submit_string_event_spec() -> Tuple[Var[dict[str, str]]]:
     """Event handler spec for the on_submit event.
     """Event handler spec for the on_submit event.
 
 
     Returns:
     Returns:

+ 4 - 4
reflex/components/el/elements/forms.pyi

@@ -270,8 +270,8 @@ class Fieldset(Element):
         """
         """
         ...
         ...
 
 
-def on_submit_event_spec() -> Tuple[Var[Dict[str, Any]]]: ...
-def on_submit_string_event_spec() -> Tuple[Var[Dict[str, str]]]: ...
+def on_submit_event_spec() -> Tuple[Var[dict[str, Any]]]: ...
+def on_submit_string_event_spec() -> Tuple[Var[dict[str, str]]]: ...
 
 
 class Form(BaseHTML):
 class Form(BaseHTML):
     @overload
     @overload
@@ -341,10 +341,10 @@ class Form(BaseHTML):
         on_submit: Optional[
         on_submit: Optional[
             Union[
             Union[
                 Union[
                 Union[
-                    EventType[[], BASE_STATE], EventType[[Dict[str, Any]], BASE_STATE]
+                    EventType[[], BASE_STATE], EventType[[dict[str, Any]], BASE_STATE]
                 ],
                 ],
                 Union[
                 Union[
-                    EventType[[], BASE_STATE], EventType[[Dict[str, str]], BASE_STATE]
+                    EventType[[], BASE_STATE], EventType[[dict[str, str]], BASE_STATE]
                 ],
                 ],
             ]
             ]
         ] = None,
         ] = None,

+ 6 - 6
reflex/components/radix/primitives/form.pyi

@@ -132,10 +132,10 @@ class FormRoot(FormComponent, HTMLForm):
         on_submit: Optional[
         on_submit: Optional[
             Union[
             Union[
                 Union[
                 Union[
-                    EventType[[], BASE_STATE], EventType[[Dict[str, Any]], BASE_STATE]
+                    EventType[[], BASE_STATE], EventType[[dict[str, Any]], BASE_STATE]
                 ],
                 ],
                 Union[
                 Union[
-                    EventType[[], BASE_STATE], EventType[[Dict[str, str]], BASE_STATE]
+                    EventType[[], BASE_STATE], EventType[[dict[str, str]], BASE_STATE]
                 ],
                 ],
             ]
             ]
         ] = None,
         ] = None,
@@ -608,10 +608,10 @@ class Form(FormRoot):
         on_submit: Optional[
         on_submit: Optional[
             Union[
             Union[
                 Union[
                 Union[
-                    EventType[[], BASE_STATE], EventType[[Dict[str, Any]], BASE_STATE]
+                    EventType[[], BASE_STATE], EventType[[dict[str, Any]], BASE_STATE]
                 ],
                 ],
                 Union[
                 Union[
-                    EventType[[], BASE_STATE], EventType[[Dict[str, str]], BASE_STATE]
+                    EventType[[], BASE_STATE], EventType[[dict[str, str]], BASE_STATE]
                 ],
                 ],
             ]
             ]
         ] = None,
         ] = None,
@@ -741,10 +741,10 @@ class FormNamespace(ComponentNamespace):
         on_submit: Optional[
         on_submit: Optional[
             Union[
             Union[
                 Union[
                 Union[
-                    EventType[[], BASE_STATE], EventType[[Dict[str, Any]], BASE_STATE]
+                    EventType[[], BASE_STATE], EventType[[dict[str, Any]], BASE_STATE]
                 ],
                 ],
                 Union[
                 Union[
-                    EventType[[], BASE_STATE], EventType[[Dict[str, str]], BASE_STATE]
+                    EventType[[], BASE_STATE], EventType[[dict[str, str]], BASE_STATE]
                 ],
                 ],
             ]
             ]
         ] = None,
         ] = None,

+ 64 - 114
reflex/event.py

@@ -25,7 +25,6 @@ from typing import (
     overload,
     overload,
 )
 )
 
 
-import typing_extensions
 from typing_extensions import (
 from typing_extensions import (
     Concatenate,
     Concatenate,
     ParamSpec,
     ParamSpec,
@@ -40,7 +39,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 (
+    EventFnArgMismatchError,
+    EventHandlerArgTypeMismatchError,
+    MissingAnnotationError,
+)
 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
@@ -96,32 +99,6 @@ _EVENT_FIELDS: set[str] = {f.name for f in dataclasses.fields(Event)}
 BACKGROUND_TASK_MARKER = "_reflex_background_task"
 BACKGROUND_TASK_MARKER = "_reflex_background_task"
 
 
 
 
-def background(fn, *, __internal_reflex_call: bool = False):
-    """Decorator to mark event handler as running in the background.
-
-    Args:
-        fn: The function to decorate.
-
-    Returns:
-        The same function, but with a marker set.
-
-
-    Raises:
-        TypeError: If the function is not a coroutine function or async generator.
-    """
-    if not __internal_reflex_call:
-        console.deprecate(
-            "background-decorator",
-            "Use `rx.event(background=True)` instead.",
-            "0.6.5",
-            "0.7.0",
-        )
-    if not inspect.iscoroutinefunction(fn) and not inspect.isasyncgenfunction(fn):
-        raise TypeError("Background task must be async function or generator.")
-    setattr(fn, BACKGROUND_TASK_MARKER, True)
-    return fn
-
-
 @dataclasses.dataclass(
 @dataclasses.dataclass(
     init=True,
     init=True,
     frozen=True,
     frozen=True,
@@ -813,29 +790,10 @@ def server_side(name: str, sig: inspect.Signature, **kwargs) -> EventSpec:
     )
     )
 
 
 
 
-@overload
-def redirect(
-    path: str | Var[str],
-    is_external: Optional[bool] = None,
-    replace: bool = False,
-) -> EventSpec: ...
-
-
-@overload
-@typing_extensions.deprecated("`external` is deprecated use `is_external` instead")
 def redirect(
 def redirect(
     path: str | Var[str],
     path: str | Var[str],
-    is_external: Optional[bool] = None,
+    is_external: bool = False,
     replace: bool = False,
     replace: bool = False,
-    external: Optional[bool] = None,
-) -> EventSpec: ...
-
-
-def redirect(
-    path: str | Var[str],
-    is_external: Optional[bool] = None,
-    replace: bool = False,
-    external: Optional[bool] = None,
 ) -> EventSpec:
 ) -> EventSpec:
     """Redirect to a new path.
     """Redirect to a new path.
 
 
@@ -843,26 +801,10 @@ def redirect(
         path: The path to redirect to.
         path: The path to redirect to.
         is_external: Whether to open in new tab or not.
         is_external: Whether to open in new tab or not.
         replace: If True, the current page will not create a new history entry.
         replace: If True, the current page will not create a new history entry.
-        external(Deprecated): Whether to open in new tab or not.
 
 
     Returns:
     Returns:
         An event to redirect to the path.
         An event to redirect to the path.
     """
     """
-    if external is not None:
-        console.deprecate(
-            "The `external` prop in `rx.redirect`",
-            "use `is_external` instead.",
-            "0.6.6",
-            "0.7.0",
-        )
-
-    # is_external should take precedence over external.
-    is_external = (
-        (False if external is None else external)
-        if is_external is None
-        else is_external
-    )
-
     return server_side(
     return server_side(
         "_redirect",
         "_redirect",
         get_fn_signature(redirect),
         get_fn_signature(redirect),
@@ -1279,11 +1221,14 @@ 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:
+        EventHandlerArgTypeMismatchError: If the event handler arguments do not match the event spec. #noqa: DAR402
+        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
-
+    #noqa: DAR401
     """
     """
     event_spec_args = parse_args_spec(event_spec)  # type: ignore
     event_spec_args = parse_args_spec(event_spec)  # type: ignore
 
 
@@ -1320,10 +1265,15 @@ def call_event_handler(
             ),
             ),
         )
         )
     )
     )
+    type_match_found: dict[str, bool] = {}
+    delayed_exceptions: list[EventHandlerArgTypeMismatchError] = []
 
 
-    if event_spec_return_types:
-        failures = []
+    try:
+        type_hints_of_provided_callback = get_type_hints(event_callback.fn)
+    except NameError:
+        type_hints_of_provided_callback = {}
 
 
+    if event_spec_return_types:
         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(
@@ -1335,43 +1285,35 @@ def call_event_handler(
                 arg if get_origin(arg) is not Var else get_args(arg)[0] for arg in args
                 arg if get_origin(arg) is not Var else get_args(arg)[0] for arg in args
             ]
             ]
 
 
-            try:
-                type_hints_of_provided_callback = get_type_hints(event_callback.fn)
-            except NameError:
-                type_hints_of_provided_callback = {}
-
-            failed_type_check = False
-
             # check that args of event handler are matching the spec if type hints are provided
             # check that args of event handler are matching the spec if type hints are provided
             for i, arg in enumerate(event_callback_spec.args[1:]):
             for i, arg in enumerate(event_callback_spec.args[1:]):
                 if arg not in type_hints_of_provided_callback:
                 if arg not in type_hints_of_provided_callback:
                     continue
                     continue
 
 
+                type_match_found.setdefault(arg, False)
+
                 try:
                 try:
                     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:
-                    # 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}."
                         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:
                 if compare_result:
+                    type_match_found[arg] = True
                     continue
                     continue
                 else:
                 else:
-                    failure = 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."
+                    type_match_found[arg] = False
+                    delayed_exceptions.append(
+                        EventHandlerArgTypeMismatchError(
+                            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 all(type_match_found.values()):
+                delayed_exceptions.clear()
                 if event_spec_index:
                 if event_spec_index:
                     args = get_args(event_spec_return_types[0])
                     args = get_args(event_spec_return_types[0])
 
 
@@ -1393,15 +1335,10 @@ def call_event_handler(
                         f"Event handler {key} expects ({expect_string}) -> () but got ({given_string}) -> () as annotated in {event_callback.fn.__qualname__} instead. "
                         f"Event handler {key} expects ({expect_string}) -> () but got ({given_string}) -> () as annotated in {event_callback.fn.__qualname__} instead. "
                         f"This may lead to unexpected behavior but is intentionally ignored for {key}."
                         f"This may lead to unexpected behavior but is intentionally ignored for {key}."
                     )
                     )
-                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",
-            )
+                break
+
+    if delayed_exceptions:
+        raise delayed_exceptions[0]
 
 
     return event_callback(*event_spec_args)  # type: ignore
     return event_callback(*event_spec_args)  # type: ignore
 
 
@@ -1420,26 +1357,26 @@ def unwrap_var_annotation(annotation: GenericType):
     return annotation
     return annotation
 
 
 
 
-def resolve_annotation(annotations: dict[str, Any], arg_name: str):
+def resolve_annotation(annotations: dict[str, Any], arg_name: str, spec: ArgsSpec):
     """Resolve the annotation for the given argument name.
     """Resolve the annotation for the given argument name.
 
 
     Args:
     Args:
         annotations: The annotations.
         annotations: The annotations.
         arg_name: The argument name.
         arg_name: The argument name.
+        spec: The specs which the annotations come from.
+
+    Raises:
+        MissingAnnotationError: If the annotation is missing for non-lambda methods.
 
 
     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(
-            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]
+        if not isinstance(spec, types.LambdaType):
+            raise MissingAnnotationError(var_name=arg_name)
+        else:
+            return dict[str, dict]
     return annotation
     return annotation
 
 
 
 
@@ -1461,7 +1398,13 @@ def parse_args_spec(arg_spec: ArgsSpec | Sequence[ArgsSpec]):
         arg_spec(
         arg_spec(
             *[
             *[
                 Var(f"_{l_arg}").to(
                 Var(f"_{l_arg}").to(
-                    unwrap_var_annotation(resolve_annotation(annotations, l_arg))
+                    unwrap_var_annotation(
+                        resolve_annotation(
+                            annotations,
+                            l_arg,
+                            spec=arg_spec,
+                        )
+                    )
                 )
                 )
                 for l_arg in spec.args
                 for l_arg in spec.args
             ]
             ]
@@ -1477,7 +1420,7 @@ def check_fn_match_arg_spec(
     func_name: str | None = None,
     func_name: str | None = None,
 ):
 ):
     """Ensures that the function signature matches the passed argument specification
     """Ensures that the function signature matches the passed argument specification
-    or raises an EventFnArgMismatch if they do not.
+    or raises an EventFnArgMismatchError if they do not.
 
 
     Args:
     Args:
         user_func: The function to be validated.
         user_func: The function to be validated.
@@ -1487,7 +1430,7 @@ def check_fn_match_arg_spec(
         func_name: The name of the function to be validated.
         func_name: The name of the function to be validated.
 
 
     Raises:
     Raises:
-        EventFnArgMismatch: Raised if the number of mandatory arguments do not match
+        EventFnArgMismatchError: Raised if the number of mandatory arguments do not match
     """
     """
     user_args = inspect.getfullargspec(user_func).args
     user_args = inspect.getfullargspec(user_func).args
     # Drop the first argument if it's a bound method
     # Drop the first argument if it's a bound method
@@ -1503,7 +1446,7 @@ def check_fn_match_arg_spec(
     number_of_event_args = len(parsed_event_args)
     number_of_event_args = len(parsed_event_args)
 
 
     if number_of_user_args - number_of_user_default_args > number_of_event_args:
     if number_of_user_args - number_of_user_default_args > number_of_event_args:
-        raise EventFnArgMismatch(
+        raise EventFnArgMismatchError(
             f"Event {key} only provides {number_of_event_args} arguments, but "
             f"Event {key} only provides {number_of_event_args} arguments, but "
             f"{func_name or user_func} requires at least {number_of_user_args - number_of_user_default_args} "
             f"{func_name or user_func} requires at least {number_of_user_args - number_of_user_default_args} "
             "arguments to be passed to the event handler.\n"
             "arguments to be passed to the event handler.\n"
@@ -1812,8 +1755,6 @@ V3 = TypeVar("V3")
 V4 = TypeVar("V4")
 V4 = TypeVar("V4")
 V5 = TypeVar("V5")
 V5 = TypeVar("V5")
 
 
-background_event_decorator = background
-
 
 
 class EventCallback(Generic[P, T]):
 class EventCallback(Generic[P, T]):
     """A descriptor that wraps a function to be used as an event."""
     """A descriptor that wraps a function to be used as an event."""
@@ -1986,6 +1927,9 @@ class EventNamespace(types.SimpleNamespace):
             func: The function to wrap.
             func: The function to wrap.
             background: Whether the event should be run in the background. Defaults to False.
             background: Whether the event should be run in the background. Defaults to False.
 
 
+        Raises:
+            TypeError: If background is True and the function is not a coroutine or async generator. # noqa: DAR402
+
         Returns:
         Returns:
             The wrapped function.
             The wrapped function.
         """
         """
@@ -1994,7 +1938,13 @@ class EventNamespace(types.SimpleNamespace):
             func: Callable[Concatenate[BASE_STATE, P], T],
             func: Callable[Concatenate[BASE_STATE, P], T],
         ) -> EventCallback[P, T]:
         ) -> EventCallback[P, T]:
             if background is True:
             if background is True:
-                return background_event_decorator(func, __internal_reflex_call=True)  # type: ignore
+                if not inspect.iscoroutinefunction(
+                    func
+                ) and not inspect.isasyncgenfunction(func):
+                    raise TypeError(
+                        "Background task must be async function or generator."
+                    )
+                setattr(func, BACKGROUND_TASK_MARKER, True)
             return func  # type: ignore
             return func  # type: ignore
 
 
         if func is not None:
         if func is not None:

+ 0 - 2
reflex/experimental/__init__.py

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

+ 0 - 37
reflex/experimental/assets.py

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

+ 19 - 6
reflex/reflex.py

@@ -505,6 +505,7 @@ def deploy(
     ),
     ),
 ):
 ):
     """Deploy the app to the Reflex hosting service."""
     """Deploy the app to the Reflex hosting service."""
+    from reflex_cli.constants.base import LogLevel as HostingLogLevel
     from reflex_cli.utils import dependency
     from reflex_cli.utils import dependency
     from reflex_cli.v2 import cli as hosting_cli
     from reflex_cli.v2 import cli as hosting_cli
 
 
@@ -516,6 +517,21 @@ def deploy(
     # Set the log level.
     # Set the log level.
     console.set_log_level(loglevel)
     console.set_log_level(loglevel)
 
 
+    def convert_reflex_loglevel_to_reflex_cli_loglevel(
+        loglevel: constants.LogLevel,
+    ) -> HostingLogLevel:
+        if loglevel == constants.LogLevel.DEBUG:
+            return HostingLogLevel.DEBUG
+        if loglevel == constants.LogLevel.INFO:
+            return HostingLogLevel.INFO
+        if loglevel == constants.LogLevel.WARNING:
+            return HostingLogLevel.WARNING
+        if loglevel == constants.LogLevel.ERROR:
+            return HostingLogLevel.ERROR
+        if loglevel == constants.LogLevel.CRITICAL:
+            return HostingLogLevel.CRITICAL
+        return HostingLogLevel.INFO
+
     # Only check requirements if interactive.
     # Only check requirements if interactive.
     # There is user interaction for requirements update.
     # There is user interaction for requirements update.
     if interactive:
     if interactive:
@@ -525,9 +541,7 @@ def deploy(
     if prerequisites.needs_reinit(frontend=True):
     if prerequisites.needs_reinit(frontend=True):
         _init(name=config.app_name, loglevel=loglevel)
         _init(name=config.app_name, loglevel=loglevel)
     prerequisites.check_latest_package_version(constants.ReflexHostingCLI.MODULE_NAME)
     prerequisites.check_latest_package_version(constants.ReflexHostingCLI.MODULE_NAME)
-    extra: dict[str, str] = (
-        {"config_path": config_path} if config_path is not None else {}
-    )
+
     hosting_cli.deploy(
     hosting_cli.deploy(
         app_name=app_name,
         app_name=app_name,
         app_id=app_id,
         app_id=app_id,
@@ -551,12 +565,11 @@ def deploy(
         envfile=envfile,
         envfile=envfile,
         hostname=hostname,
         hostname=hostname,
         interactive=interactive,
         interactive=interactive,
-        loglevel=type(loglevel).INFO,  # type: ignore
+        loglevel=convert_reflex_loglevel_to_reflex_cli_loglevel(loglevel),
         token=token,
         token=token,
         project=project,
         project=project,
-        config_path=config_path,
         project_name=project_name,
         project_name=project_name,
-        **extra,
+        **({"config_path": config_path} if config_path is not None else {}),
     )
     )
 
 
 
 

+ 4 - 7
reflex/state.py

@@ -1341,12 +1341,9 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
             if field.allow_none and not is_optional(field_type):
             if field.allow_none and not is_optional(field_type):
                 field_type = Union[field_type, None]
                 field_type = Union[field_type, None]
             if not _isinstance(value, field_type):
             if not _isinstance(value, field_type):
-                console.deprecate(
-                    "mismatched-type-assignment",
-                    f"Tried to assign value {value} of type {type(value)} to field {type(self).__name__}.{name} of type {field_type}."
-                    " This might lead to unexpected behavior.",
-                    "0.6.5",
-                    "0.7.0",
+                console.error(
+                    f"Expected field '{type(self).__name__}.{name}' to receive type '{field_type}',"
+                    f" but got '{value}' of type '{type(value)}'."
                 )
                 )
 
 
         # Set the attribute.
         # Set the attribute.
@@ -1831,7 +1828,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

+ 3 - 1
reflex/style.py

@@ -287,7 +287,9 @@ class Style(dict):
         _var = LiteralVar.create(value)
         _var = LiteralVar.create(value)
         if _var is not None:
         if _var is not None:
             # Carry the imports/hooks when setting a Var as a value.
             # Carry the imports/hooks when setting a Var as a value.
-            self._var_data = VarData.merge(self._var_data, _var._get_all_var_data())
+            self._var_data = VarData.merge(
+                getattr(self, "_var_data", None), _var._get_all_var_data()
+            )
         super().__setitem__(key, value)
         super().__setitem__(key, value)
 
 
 
 

+ 3 - 11
reflex/utils/console.py

@@ -51,20 +51,12 @@ def set_log_level(log_level: LogLevel):
         log_level: The log level to set.
         log_level: The log level to set.
 
 
     Raises:
     Raises:
-        ValueError: If the log level is invalid.
+        TypeError: If the log level is a string.
     """
     """
     if not isinstance(log_level, LogLevel):
     if not isinstance(log_level, LogLevel):
-        deprecate(
-            feature_name="Passing a string to set_log_level",
-            reason="use reflex.constants.LogLevel enum instead",
-            deprecation_version="0.6.6",
-            removal_version="0.7.0",
+        raise TypeError(
+            f"log_level must be a LogLevel enum value, got {log_level} of type {type(log_level)} instead."
         )
         )
-        try:
-            log_level = getattr(LogLevel, log_level.upper())
-        except AttributeError as ae:
-            raise ValueError(f"Invalid log level: {log_level}") from ae
-
     global _LOG_LEVEL
     global _LOG_LEVEL
     _LOG_LEVEL = log_level
     _LOG_LEVEL = log_level
 
 

+ 42 - 20
reflex/utils/exceptions.py

@@ -1,6 +1,6 @@
 """Custom Exceptions."""
 """Custom Exceptions."""
 
 
-from typing import Any, NoReturn
+from typing import Any
 
 
 
 
 class ReflexError(Exception):
 class ReflexError(Exception):
@@ -75,6 +75,30 @@ class VarAttributeError(ReflexError, AttributeError):
     """Custom AttributeError for var related errors."""
     """Custom AttributeError for var related errors."""
 
 
 
 
+class UntypedComputedVarError(ReflexError, TypeError):
+    """Custom TypeError for untyped computed var errors."""
+
+    def __init__(self, var_name):
+        """Initialize the UntypedComputedVarError.
+
+        Args:
+            var_name: The name of the computed var.
+        """
+        super().__init__(f"Computed var '{var_name}' must have a type annotation.")
+
+
+class MissingAnnotationError(ReflexError, TypeError):
+    """Custom TypeError for missing annotations."""
+
+    def __init__(self, var_name):
+        """Initialize the MissingAnnotationError.
+
+        Args:
+            var_name: The name of the var.
+        """
+        super().__init__(f"Var '{var_name}' must have a type annotation.")
+
+
 class UploadValueError(ReflexError, ValueError):
 class UploadValueError(ReflexError, ValueError):
     """Custom ValueError for upload related errors."""
     """Custom ValueError for upload related errors."""
 
 
@@ -111,11 +135,11 @@ class MatchTypeError(ReflexError, TypeError):
     """Raised when the return types of match cases are different."""
     """Raised when the return types of match cases are different."""
 
 
 
 
-class EventHandlerArgTypeMismatch(ReflexError, TypeError):
+class EventHandlerArgTypeMismatchError(ReflexError, TypeError):
     """Raised when the annotations of args accepted by an EventHandler differs from the spec of the event trigger."""
     """Raised when the annotations of args accepted by an EventHandler differs from the spec of the event trigger."""
 
 
 
 
-class EventFnArgMismatch(ReflexError, TypeError):
+class EventFnArgMismatchError(ReflexError, TypeError):
     """Raised when the number of args required by an event handler is more than provided by the event trigger."""
     """Raised when the number of args required by an event handler is more than provided by the event trigger."""
 
 
 
 
@@ -186,27 +210,25 @@ class StateMismatchError(ReflexError, ValueError):
 class SystemPackageMissingError(ReflexError):
 class SystemPackageMissingError(ReflexError):
     """Raised when a system package is missing."""
     """Raised when a system package is missing."""
 
 
+    def __init__(self, package: str):
+        """Initialize the SystemPackageMissingError.
 
 
-class EventDeserializationError(ReflexError, ValueError):
-    """Raised when an event cannot be deserialized."""
-
-
-def raise_system_package_missing_error(package: str) -> NoReturn:
-    """Raise a SystemPackageMissingError.
+        Args:
+            package: The missing package.
+        """
+        from reflex.constants import IS_MACOS
 
 
-    Args:
-        package: The name of the missing system package.
+        extra = (
+            f" You can do so by running 'brew install {package}'." if IS_MACOS else ""
+        )
+        super().__init__(
+            f"System package '{package}' is missing."
+            f" Please install it through your system package manager.{extra}"
+        )
 
 
-    Raises:
-        SystemPackageMissingError: The raised exception.
-    """
-    from reflex.constants import IS_MACOS
 
 
-    raise SystemPackageMissingError(
-        f"System package '{package}' is missing."
-        " Please install it through your system package manager."
-        + (f" You can do so by running 'brew install {package}'." if IS_MACOS else "")
-    )
+class EventDeserializationError(ReflexError, ValueError):
+    """Raised when an event cannot be deserialized."""
 
 
 
 
 class InvalidLockWarningThresholdError(ReflexError):
 class InvalidLockWarningThresholdError(ReflexError):

+ 12 - 54
reflex/utils/exec.py

@@ -240,25 +240,28 @@ def run_backend(
         run_uvicorn_backend(host, port, loglevel)
         run_uvicorn_backend(host, port, loglevel)
 
 
 
 
-def get_reload_dirs() -> list[str]:
+def get_reload_dirs() -> list[Path]:
     """Get the reload directories for the backend.
     """Get the reload directories for the backend.
 
 
     Returns:
     Returns:
         The reload directories for the backend.
         The reload directories for the backend.
     """
     """
     config = get_config()
     config = get_config()
-    reload_dirs = [config.app_name]
+    reload_dirs = [Path(config.app_name)]
     if config.app_module is not None and config.app_module.__file__:
     if config.app_module is not None and config.app_module.__file__:
         module_path = Path(config.app_module.__file__).resolve().parent
         module_path = Path(config.app_module.__file__).resolve().parent
+
         while module_path.parent.name:
         while module_path.parent.name:
-            for parent_file in module_path.parent.iterdir():
-                if parent_file == "__init__.py":
-                    # go up a level to find dir without `__init__.py`
-                    module_path = module_path.parent
-                    break
+            if any(
+                sibling_file.name == "__init__.py"
+                for sibling_file in module_path.parent.iterdir()
+            ):
+                # go up a level to find dir without `__init__.py`
+                module_path = module_path.parent
             else:
             else:
                 break
                 break
-        reload_dirs.append(str(module_path))
+
+        reload_dirs = [module_path]
     return reload_dirs
     return reload_dirs
 
 
 
 
@@ -278,7 +281,7 @@ def run_uvicorn_backend(host, port, loglevel: LogLevel):
         port=port,
         port=port,
         log_level=loglevel.value,
         log_level=loglevel.value,
         reload=True,
         reload=True,
-        reload_dirs=get_reload_dirs(),
+        reload_dirs=list(map(str, get_reload_dirs())),
     )
     )
 
 
 
 
@@ -526,48 +529,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()

+ 0 - 32
reflex/utils/format.py

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

+ 7 - 17
reflex/utils/prerequisites.py

@@ -38,7 +38,7 @@ from reflex.config import Config, environment, get_config
 from reflex.utils import console, net, path_ops, processes, redir
 from reflex.utils import console, net, path_ops, processes, redir
 from reflex.utils.exceptions import (
 from reflex.utils.exceptions import (
     GeneratedCodeHasNoFunctionDefs,
     GeneratedCodeHasNoFunctionDefs,
-    raise_system_package_missing_error,
+    SystemPackageMissingError,
 )
 )
 from reflex.utils.format import format_library_name
 from reflex.utils.format import format_library_name
 from reflex.utils.registry import _get_npm_registry
 from reflex.utils.registry import _get_npm_registry
@@ -86,18 +86,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.
 
 
@@ -120,8 +108,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
 
 
@@ -885,7 +871,11 @@ def install_node():
 
 
 
 
 def install_bun():
 def install_bun():
-    """Install bun onto the user's system."""
+    """Install bun onto the user's system.
+
+    Raises:
+        SystemPackageMissingError: If "unzip" is missing.
+    """
     win_supported = is_windows_bun_supported()
     win_supported = is_windows_bun_supported()
     one_drive_in_path = windows_check_onedrive_in_path()
     one_drive_in_path = windows_check_onedrive_in_path()
     if constants.IS_WINDOWS and (not win_supported or one_drive_in_path):
     if constants.IS_WINDOWS and (not win_supported or one_drive_in_path):
@@ -924,7 +914,7 @@ def install_bun():
     else:
     else:
         unzip_path = path_ops.which("unzip")
         unzip_path = path_ops.which("unzip")
         if unzip_path is None:
         if unzip_path is None:
-            raise_system_package_missing_error("unzip")
+            raise SystemPackageMissingError("unzip")
 
 
         # Run the bun install script.
         # Run the bun install script.
         download_and_run(
         download_and_run(

+ 1 - 1
reflex/utils/telemetry.py

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

+ 7 - 44
reflex/vars/base.py

@@ -46,6 +46,7 @@ from reflex.base import Base
 from reflex.constants.compiler import Hooks
 from reflex.constants.compiler import Hooks
 from reflex.utils import console, exceptions, imports, serializers, types
 from reflex.utils import console, exceptions, imports, serializers, types
 from reflex.utils.exceptions import (
 from reflex.utils.exceptions import (
+    UntypedComputedVarError,
     VarAttributeError,
     VarAttributeError,
     VarDependencyError,
     VarDependencyError,
     VarTypeError,
     VarTypeError,
@@ -545,52 +546,21 @@ 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
 
 
-        # Try to pull the imports and hooks from contained values.
-        if not isinstance(value, str):
-            return LiteralVar.create(value, _var_data=_var_data)
-
-        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
@@ -1863,19 +1833,14 @@ class ComputedVar(Var[RETURN_TYPE]):
 
 
         Raises:
         Raises:
             TypeError: If the computed var dependencies are not Var instances or var names.
             TypeError: If the computed var dependencies are not Var instances or var names.
+            UntypedComputedVarError: If the computed var is untyped.
         """
         """
         hint = kwargs.pop("return_type", None) or get_type_hints(fget).get(
         hint = kwargs.pop("return_type", None) or get_type_hints(fget).get(
             "return", Any
             "return", Any
         )
         )
 
 
         if hint is Any:
         if hint is Any:
-            console.deprecate(
-                "untyped-computed-var",
-                "ComputedVar should have a return type annotation.",
-                "0.6.5",
-                "0.7.0",
-            )
-
+            raise UntypedComputedVarError(var_name=fget.__name__)
         kwargs.setdefault("_js_expr", fget.__name__)
         kwargs.setdefault("_js_expr", fget.__name__)
         kwargs.setdefault("_var_type", hint)
         kwargs.setdefault("_var_type", hint)
 
 
@@ -1948,6 +1913,7 @@ class ComputedVar(Var[RETURN_TYPE]):
             "_var_data": kwargs.pop(
             "_var_data": kwargs.pop(
                 "_var_data", VarData.merge(self._var_data, merge_var_data)
                 "_var_data", VarData.merge(self._var_data, merge_var_data)
             ),
             ),
+            "return_type": kwargs.pop("return_type", self._var_type),
         }
         }
 
 
         if kwargs:
         if kwargs:
@@ -2082,12 +2048,9 @@ class ComputedVar(Var[RETURN_TYPE]):
             value = getattr(instance, self._cache_attr)
             value = getattr(instance, self._cache_attr)
 
 
         if not _isinstance(value, self._var_type):
         if not _isinstance(value, self._var_type):
-            console.deprecate(
-                "mismatched-computed-var-return",
-                f"Computed var {type(instance).__name__}.{self._js_expr} returned value of type {type(value)}, "
-                f"expected {self._var_type}. This might cause unexpected behavior.",
-                "0.6.5",
-                "0.7.0",
+            console.error(
+                f"Computed var '{type(instance).__name__}.{self._js_expr}' must return"
+                f" type '{self._var_type}', got '{type(value)}'."
             )
             )
 
 
         return value
         return value

+ 1 - 1
tests/integration/init-test/Dockerfile

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

+ 25 - 23
tests/integration/test_call_script.py

@@ -16,7 +16,7 @@ from .utils import SessionStorage
 def CallScript():
 def CallScript():
     """A test app for browser javascript integration."""
     """A test app for browser javascript integration."""
     from pathlib import Path
     from pathlib import Path
-    from typing import Dict, List, Optional, Union
+    from typing import Optional, Union
 
 
     import reflex as rx
     import reflex as rx
 
 
@@ -43,15 +43,17 @@ def CallScript():
     external_scripts = inline_scripts.replace("inline", "external")
     external_scripts = inline_scripts.replace("inline", "external")
 
 
     class CallScriptState(rx.State):
     class CallScriptState(rx.State):
-        results: List[Optional[Union[str, Dict, List]]] = []
-        inline_counter: int = 0
-        external_counter: int = 0
+        results: rx.Field[list[Optional[Union[str, dict, list]]]] = rx.field([])
+        inline_counter: rx.Field[int] = rx.field(0)
+        external_counter: rx.Field[int] = rx.field(0)
         value: str = "Initial"
         value: str = "Initial"
-        last_result: str = ""
+        last_result: int = 0
 
 
+        @rx.event
         def call_script_callback(self, result):
         def call_script_callback(self, result):
             self.results.append(result)
             self.results.append(result)
 
 
+        @rx.event
         def call_script_callback_other_arg(self, result, other_arg):
         def call_script_callback_other_arg(self, result, other_arg):
             self.results.append([other_arg, result])
             self.results.append([other_arg, result])
 
 
@@ -91,7 +93,7 @@ def CallScript():
         def call_script_inline_return_lambda(self):
         def call_script_inline_return_lambda(self):
             return rx.call_script(
             return rx.call_script(
                 "inline2()",
                 "inline2()",
-                callback=lambda result: CallScriptState.call_script_callback_other_arg(  # type: ignore
+                callback=lambda result: CallScriptState.call_script_callback_other_arg(
                     result, "lambda"
                     result, "lambda"
                 ),
                 ),
             )
             )
@@ -100,7 +102,7 @@ def CallScript():
         def get_inline_counter(self):
         def get_inline_counter(self):
             return rx.call_script(
             return rx.call_script(
                 "inline_counter",
                 "inline_counter",
-                callback=CallScriptState.set_inline_counter,  # type: ignore
+                callback=CallScriptState.setvar("inline_counter"),
             )
             )
 
 
         @rx.event
         @rx.event
@@ -139,7 +141,7 @@ def CallScript():
         def call_script_external_return_lambda(self):
         def call_script_external_return_lambda(self):
             return rx.call_script(
             return rx.call_script(
                 "external2()",
                 "external2()",
-                callback=lambda result: CallScriptState.call_script_callback_other_arg(  # type: ignore
+                callback=lambda result: CallScriptState.call_script_callback_other_arg(
                     result, "lambda"
                     result, "lambda"
                 ),
                 ),
             )
             )
@@ -148,28 +150,28 @@ def CallScript():
         def get_external_counter(self):
         def get_external_counter(self):
             return rx.call_script(
             return rx.call_script(
                 "external_counter",
                 "external_counter",
-                callback=CallScriptState.set_external_counter,  # type: ignore
+                callback=CallScriptState.setvar("external_counter"),
             )
             )
 
 
         @rx.event
         @rx.event
         def call_with_var_f_string(self):
         def call_with_var_f_string(self):
             return rx.call_script(
             return rx.call_script(
                 f"{rx.Var('inline_counter')} + {rx.Var('external_counter')}",
                 f"{rx.Var('inline_counter')} + {rx.Var('external_counter')}",
-                callback=CallScriptState.set_last_result,  # type: ignore
+                callback=CallScriptState.setvar("last_result"),
             )
             )
 
 
         @rx.event
         @rx.event
         def call_with_var_str_cast(self):
         def call_with_var_str_cast(self):
             return rx.call_script(
             return rx.call_script(
                 f"{rx.Var('inline_counter')!s} + {rx.Var('external_counter')!s}",
                 f"{rx.Var('inline_counter')!s} + {rx.Var('external_counter')!s}",
-                callback=CallScriptState.set_last_result,  # type: ignore
+                callback=CallScriptState.setvar("last_result"),
             )
             )
 
 
         @rx.event
         @rx.event
         def call_with_var_f_string_wrapped(self):
         def call_with_var_f_string_wrapped(self):
             return rx.call_script(
             return rx.call_script(
                 rx.Var(f"{rx.Var('inline_counter')} + {rx.Var('external_counter')}"),
                 rx.Var(f"{rx.Var('inline_counter')} + {rx.Var('external_counter')}"),
-                callback=CallScriptState.set_last_result,  # type: ignore
+                callback=CallScriptState.setvar("last_result"),
             )
             )
 
 
         @rx.event
         @rx.event
@@ -178,7 +180,7 @@ def CallScript():
                 rx.Var(
                 rx.Var(
                     f"{rx.Var('inline_counter')!s} + {rx.Var('external_counter')!s}"
                     f"{rx.Var('inline_counter')!s} + {rx.Var('external_counter')!s}"
                 ),
                 ),
-                callback=CallScriptState.set_last_result,  # type: ignore
+                callback=CallScriptState.setvar("last_result"),
             )
             )
 
 
         @rx.event
         @rx.event
@@ -193,17 +195,17 @@ def CallScript():
     def index():
     def index():
         return rx.vstack(
         return rx.vstack(
             rx.input(
             rx.input(
-                value=CallScriptState.inline_counter.to(str),  # type: ignore
+                value=CallScriptState.inline_counter.to(str),
                 id="inline_counter",
                 id="inline_counter",
                 read_only=True,
                 read_only=True,
             ),
             ),
             rx.input(
             rx.input(
-                value=CallScriptState.external_counter.to(str),  # type: ignore
+                value=CallScriptState.external_counter.to(str),
                 id="external_counter",
                 id="external_counter",
                 read_only=True,
                 read_only=True,
             ),
             ),
             rx.text_area(
             rx.text_area(
-                value=CallScriptState.results.to_string(),  # type: ignore
+                value=CallScriptState.results.to_string(),
                 id="results",
                 id="results",
                 read_only=True,
                 read_only=True,
             ),
             ),
@@ -273,7 +275,7 @@ def CallScript():
                 CallScriptState.value,
                 CallScriptState.value,
                 on_click=rx.call_script(
                 on_click=rx.call_script(
                     "'updated'",
                     "'updated'",
-                    callback=CallScriptState.set_value,  # type: ignore
+                    callback=CallScriptState.setvar("value"),
                 ),
                 ),
                 id="update_value",
                 id="update_value",
             ),
             ),
@@ -282,7 +284,7 @@ def CallScript():
                 value=CallScriptState.last_result,
                 value=CallScriptState.last_result,
                 id="last_result",
                 id="last_result",
                 read_only=True,
                 read_only=True,
-                on_click=CallScriptState.set_last_result(""),  # type: ignore
+                on_click=CallScriptState.setvar("last_result", 0),
             ),
             ),
             rx.button(
             rx.button(
                 "call_with_var_f_string",
                 "call_with_var_f_string",
@@ -308,7 +310,7 @@ def CallScript():
                 "call_with_var_f_string_inline",
                 "call_with_var_f_string_inline",
                 on_click=rx.call_script(
                 on_click=rx.call_script(
                     f"{rx.Var('inline_counter')} + {CallScriptState.last_result}",
                     f"{rx.Var('inline_counter')} + {CallScriptState.last_result}",
-                    callback=CallScriptState.set_last_result,  # type: ignore
+                    callback=CallScriptState.setvar("last_result"),
                 ),
                 ),
                 id="call_with_var_f_string_inline",
                 id="call_with_var_f_string_inline",
             ),
             ),
@@ -316,7 +318,7 @@ def CallScript():
                 "call_with_var_str_cast_inline",
                 "call_with_var_str_cast_inline",
                 on_click=rx.call_script(
                 on_click=rx.call_script(
                     f"{rx.Var('inline_counter')!s} + {rx.Var('external_counter')!s}",
                     f"{rx.Var('inline_counter')!s} + {rx.Var('external_counter')!s}",
-                    callback=CallScriptState.set_last_result,  # type: ignore
+                    callback=CallScriptState.setvar("last_result"),
                 ),
                 ),
                 id="call_with_var_str_cast_inline",
                 id="call_with_var_str_cast_inline",
             ),
             ),
@@ -326,7 +328,7 @@ def CallScript():
                     rx.Var(
                     rx.Var(
                         f"{rx.Var('inline_counter')} + {CallScriptState.last_result}"
                         f"{rx.Var('inline_counter')} + {CallScriptState.last_result}"
                     ),
                     ),
-                    callback=CallScriptState.set_last_result,  # type: ignore
+                    callback=CallScriptState.setvar("last_result"),
                 ),
                 ),
                 id="call_with_var_f_string_wrapped_inline",
                 id="call_with_var_f_string_wrapped_inline",
             ),
             ),
@@ -336,7 +338,7 @@ def CallScript():
                     rx.Var(
                     rx.Var(
                         f"{rx.Var('inline_counter')!s} + {rx.Var('external_counter')!s}"
                         f"{rx.Var('inline_counter')!s} + {rx.Var('external_counter')!s}"
                     ),
                     ),
-                    callback=CallScriptState.set_last_result,  # type: ignore
+                    callback=CallScriptState.setvar("last_result"),
                 ),
                 ),
                 id="call_with_var_str_cast_wrapped_inline",
                 id="call_with_var_str_cast_wrapped_inline",
             ),
             ),
@@ -483,7 +485,7 @@ def test_call_script_w_var(
     """
     """
     assert_token(driver)
     assert_token(driver)
     last_result = driver.find_element(By.ID, "last_result")
     last_result = driver.find_element(By.ID, "last_result")
-    assert last_result.get_attribute("value") == ""
+    assert last_result.get_attribute("value") == "0"
 
 
     inline_return_button = driver.find_element(By.ID, "inline_return")
     inline_return_button = driver.find_element(By.ID, "inline_return")
 
 

+ 6 - 6
tests/integration/test_client_storage.py

@@ -33,18 +33,18 @@ def ClientSide():
     class ClientSideSubState(ClientSideState):
     class ClientSideSubState(ClientSideState):
         # cookies with default settings
         # cookies with default settings
         c1: str = rx.Cookie()
         c1: str = rx.Cookie()
-        c2: rx.Cookie = "c2 default"  # type: ignore
+        c2: str = rx.Cookie("c2 default")
 
 
         # cookies with custom settings
         # cookies with custom settings
         c3: str = rx.Cookie(max_age=2)  # expires after 2 second
         c3: str = rx.Cookie(max_age=2)  # expires after 2 second
-        c4: rx.Cookie = rx.Cookie(same_site="strict")
+        c4: str = rx.Cookie(same_site="strict")
         c5: str = rx.Cookie(path="/foo/")  # only accessible on `/foo/`
         c5: str = rx.Cookie(path="/foo/")  # only accessible on `/foo/`
         c6: str = rx.Cookie(name="c6")
         c6: str = rx.Cookie(name="c6")
         c7: str = rx.Cookie("c7 default")
         c7: str = rx.Cookie("c7 default")
 
 
         # local storage with default settings
         # local storage with default settings
         l1: str = rx.LocalStorage()
         l1: str = rx.LocalStorage()
-        l2: rx.LocalStorage = "l2 default"  # type: ignore
+        l2: str = rx.LocalStorage("l2 default")
 
 
         # local storage with custom settings
         # local storage with custom settings
         l3: str = rx.LocalStorage(name="l3")
         l3: str = rx.LocalStorage(name="l3")
@@ -56,7 +56,7 @@ def ClientSide():
 
 
         # Session storage
         # Session storage
         s1: str = rx.SessionStorage()
         s1: str = rx.SessionStorage()
-        s2: rx.SessionStorage = "s2 default"  # type: ignore
+        s2: str = rx.SessionStorage("s2 default")
         s3: str = rx.SessionStorage(name="s3")
         s3: str = rx.SessionStorage(name="s3")
 
 
         def set_l6(self, my_param: str):
         def set_l6(self, my_param: str):
@@ -87,13 +87,13 @@ def ClientSide():
             rx.input(
             rx.input(
                 placeholder="state var",
                 placeholder="state var",
                 value=ClientSideState.state_var,
                 value=ClientSideState.state_var,
-                on_change=ClientSideState.set_state_var,  # type: ignore
+                on_change=ClientSideState.setvar("state_var"),
                 id="state_var",
                 id="state_var",
             ),
             ),
             rx.input(
             rx.input(
                 placeholder="input value",
                 placeholder="input value",
                 value=ClientSideState.input_value,
                 value=ClientSideState.input_value,
-                on_change=ClientSideState.set_input_value,  # type: ignore
+                on_change=ClientSideState.setvar("input_value"),
                 id="input_value",
                 id="input_value",
             ),
             ),
             rx.button(
             rx.button(

+ 0 - 13
tests/units/assets/test_assets.py

@@ -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",
     [
     [

+ 6 - 8
tests/units/components/datadisplay/conftest.py

@@ -1,7 +1,5 @@
 """Data display component tests fixtures."""
 """Data display component tests fixtures."""
 
 
-from typing import List
-
 import pandas as pd
 import pandas as pd
 import pytest
 import pytest
 
 
@@ -54,11 +52,11 @@ def data_table_state3():
     """
     """
 
 
     class DataTableState(BaseState):
     class DataTableState(BaseState):
-        _data: List = []
-        _columns: List = ["col1", "col2"]
+        _data: list = []
+        _columns: list = ["col1", "col2"]
 
 
         @rx.var
         @rx.var
-        def data(self) -> List:
+        def data(self) -> list:
             return self._data
             return self._data
 
 
         @rx.var
         @rx.var
@@ -77,15 +75,15 @@ def data_table_state4():
     """
     """
 
 
     class DataTableState(BaseState):
     class DataTableState(BaseState):
-        _data: List = []
-        _columns: List = ["col1", "col2"]
+        _data: list = []
+        _columns: list[str] = ["col1", "col2"]
 
 
         @rx.var
         @rx.var
         def data(self):
         def data(self):
             return self._data
             return self._data
 
 
         @rx.var
         @rx.var
-        def columns(self) -> List:
+        def columns(self) -> list:
             return self._columns
             return self._columns
 
 
     return DataTableState
     return DataTableState

+ 5 - 4
tests/units/components/datadisplay/test_datatable.py

@@ -4,6 +4,7 @@ import pytest
 import reflex as rx
 import reflex as rx
 from reflex.components.gridjs.datatable import DataTable
 from reflex.components.gridjs.datatable import DataTable
 from reflex.utils import types
 from reflex.utils import types
+from reflex.utils.exceptions import UntypedComputedVarError
 from reflex.utils.serializers import serialize, serialize_dataframe
 from reflex.utils.serializers import serialize, serialize_dataframe
 
 
 
 
@@ -75,17 +76,17 @@ def test_invalid_props(props):
     [
     [
         (
         (
             "data_table_state2",
             "data_table_state2",
-            "Annotation of the computed var assigned to the data field should be provided.",
+            "Computed var 'data' must have a type annotation.",
             True,
             True,
         ),
         ),
         (
         (
             "data_table_state3",
             "data_table_state3",
-            "Annotation of the computed var assigned to the column field should be provided.",
+            "Computed var 'columns' must have a type annotation.",
             False,
             False,
         ),
         ),
         (
         (
             "data_table_state4",
             "data_table_state4",
-            "Annotation of the computed var assigned to the data field should be provided.",
+            "Computed var 'data' must have a type annotation.",
             False,
             False,
         ),
         ),
     ],
     ],
@@ -99,7 +100,7 @@ def test_computed_var_without_annotation(fixture, request, err_msg, is_data_fram
         err_msg: expected error message.
         err_msg: expected error message.
         is_data_frame: whether data field is a pandas dataframe.
         is_data_frame: whether data field is a pandas dataframe.
     """
     """
-    with pytest.raises(ValueError) as err:
+    with pytest.raises(UntypedComputedVarError) as err:
         if is_data_frame:
         if is_data_frame:
             DataTable.create(data=request.getfixturevalue(fixture).data)
             DataTable.create(data=request.getfixturevalue(fixture).data)
         else:
         else:

+ 40 - 39
tests/units/components/test_component.py

@@ -19,6 +19,7 @@ from reflex.constants import EventTriggers
 from reflex.event import (
 from reflex.event import (
     EventChain,
     EventChain,
     EventHandler,
     EventHandler,
+    JavascriptInputEvent,
     input_event,
     input_event,
     no_args_event_spec,
     no_args_event_spec,
     parse_args_spec,
     parse_args_spec,
@@ -27,7 +28,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 ChildrenTypeError, EventFnArgMismatch
+from reflex.utils.exceptions import (
+    ChildrenTypeError,
+    EventFnArgMismatchError,
+    EventHandlerArgTypeMismatchError,
+)
 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 +99,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.
@@ -818,10 +826,14 @@ def test_component_create_unpack_tuple_child(test_component, element, expected):
     assert fragment_wrapper.render() == expected
     assert fragment_wrapper.render() == expected
 
 
 
 
+class _Obj(Base):
+    custom: int = 0
+
+
 class C1State(BaseState):
 class C1State(BaseState):
     """State for testing C1 component."""
     """State for testing C1 component."""
 
 
-    def mock_handler(self, _e, _bravo, _charlie):
+    def mock_handler(self, _e: JavascriptInputEvent, _bravo: dict, _charlie: _Obj):
         """Mock handler."""
         """Mock handler."""
         pass
         pass
 
 
@@ -829,10 +841,12 @@ class C1State(BaseState):
 def test_component_event_trigger_arbitrary_args():
 def test_component_event_trigger_arbitrary_args():
     """Test that we can define arbitrary types for the args of an event trigger."""
     """Test that we can define arbitrary types for the args of an event trigger."""
 
 
-    class Obj(Base):
-        custom: int = 0
-
-    def on_foo_spec(_e, alpha: str, bravo: Dict[str, Any], charlie: Obj):
+    def on_foo_spec(
+        _e: Var[JavascriptInputEvent],
+        alpha: Var[str],
+        bravo: dict[str, Any],
+        charlie: Var[_Obj],
+    ):
         return [_e.target.value, bravo["nested"], charlie.custom + 42]
         return [_e.target.value, bravo["nested"], charlie.custom + 42]
 
 
     class C1(Component):
     class C1(Component):
@@ -845,13 +859,7 @@ 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)
-
-    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], ({  }))))}"
-    )
+    C1.create(on_foo=C1State.mock_handler)
 
 
 
 
 def test_create_custom_component(my_component):
 def test_create_custom_component(my_component):
@@ -908,30 +916,29 @@ def test_invalid_event_handler_args(component2, test_state):
         test_state: A test state.
         test_state: A test state.
     """
     """
     # EventHandler args must match
     # EventHandler args must match
-    with pytest.raises(EventFnArgMismatch):
+    with pytest.raises(EventFnArgMismatchError):
         component2.create(on_click=test_state.do_something_arg)
         component2.create(on_click=test_state.do_something_arg)
 
 
     # Multiple EventHandler args: all must match
     # Multiple EventHandler args: all must match
-    with pytest.raises(EventFnArgMismatch):
+    with pytest.raises(EventFnArgMismatchError):
         component2.create(
         component2.create(
             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):
-    #     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
-
-    # 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
+    with pytest.raises(EventHandlerArgTypeMismatchError):
+        component2.create(
+            on_user_visited_count_changed=test_state.do_something_with_bool
+        )
+    with pytest.raises(EventHandlerArgTypeMismatchError):
+        component2.create(on_user_list_changed=test_state.do_something_with_int)
+    with pytest.raises(EventHandlerArgTypeMismatchError):
+        component2.create(on_user_list_changed=test_state.do_something_with_list_int)
+
+    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.
     # lambda cannot return weird values.
     with pytest.raises(ValueError):
     with pytest.raises(ValueError):
@@ -944,15 +951,15 @@ def test_invalid_event_handler_args(component2, test_state):
         )
         )
 
 
     # lambda signature must match event trigger.
     # lambda signature must match event trigger.
-    with pytest.raises(EventFnArgMismatch):
+    with pytest.raises(EventFnArgMismatchError):
         component2.create(on_click=lambda _: test_state.do_something_arg(1))
         component2.create(on_click=lambda _: test_state.do_something_arg(1))
 
 
     # lambda returning EventHandler must match spec
     # lambda returning EventHandler must match spec
-    with pytest.raises(EventFnArgMismatch):
+    with pytest.raises(EventFnArgMismatchError):
         component2.create(on_click=lambda: test_state.do_something_arg)
         component2.create(on_click=lambda: test_state.do_something_arg)
 
 
     # Mixed EventSpec and EventHandler must match spec.
     # Mixed EventSpec and EventHandler must match spec.
-    with pytest.raises(EventFnArgMismatch):
+    with pytest.raises(EventFnArgMismatchError):
         component2.create(
         component2.create(
             on_click=lambda: [
             on_click=lambda: [
                 test_state.do_something_arg(1),
                 test_state.do_something_arg(1),
@@ -1801,21 +1808,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()

+ 3 - 4
tests/units/test_event.py

@@ -199,16 +199,15 @@ def test_event_redirect(input, output):
         input: The input for running the test.
         input: The input for running the test.
         output: The expected output to validate the test.
         output: The expected output to validate the test.
     """
     """
-    path, external, replace = input
+    path, is_external, replace = input
     kwargs = {}
     kwargs = {}
-    if external is not None:
-        kwargs["external"] = external
+    if is_external is not None:
+        kwargs["is_external"] = is_external
     if replace is not None:
     if replace is not None:
         kwargs["replace"] = replace
         kwargs["replace"] = replace
     spec = event.redirect(path, **kwargs)
     spec = event.redirect(path, **kwargs)
     assert isinstance(spec, EventSpec)
     assert isinstance(spec, EventSpec)
     assert spec.handler.fn.__qualname__ == "_redirect"
     assert spec.handler.fn.__qualname__ == "_redirect"
-
     assert format.format_event(spec) == output
     assert format.format_event(spec) == output
 
 
 
 

+ 5 - 5
tests/units/test_state.py

@@ -1144,7 +1144,7 @@ def test_child_state():
 
 
     class ChildState(MainState):
     class ChildState(MainState):
         @computed_var
         @computed_var
-        def rendered_var(self):
+        def rendered_var(self) -> int:
             return self.v
             return self.v
 
 
     ms = MainState()
     ms = MainState()
@@ -1421,7 +1421,7 @@ def test_computed_var_dependencies():
             return self.testprop
             return self.testprop
 
 
         @rx.var
         @rx.var
-        def comp_w(self):
+        def comp_w(self) -> Callable[[], int]:
             """Nested lambda.
             """Nested lambda.
 
 
             Returns:
             Returns:
@@ -1430,7 +1430,7 @@ def test_computed_var_dependencies():
             return lambda: self.w
             return lambda: self.w
 
 
         @rx.var
         @rx.var
-        def comp_x(self):
+        def comp_x(self) -> Callable[[], int]:
             """Nested function.
             """Nested function.
 
 
             Returns:
             Returns:
@@ -1443,7 +1443,7 @@ def test_computed_var_dependencies():
             return _
             return _
 
 
         @rx.var
         @rx.var
-        def comp_y(self) -> List[int]:
+        def comp_y(self) -> list[int]:
             """Comprehension iterating over attribute.
             """Comprehension iterating over attribute.
 
 
             Returns:
             Returns:
@@ -3128,7 +3128,7 @@ async def test_get_state_from_sibling_not_cached(mock_app: rx.App, token: str):
         child3_var: int = 0
         child3_var: int = 0
 
 
         @rx.var(cache=False)
         @rx.var(cache=False)
-        def v(self):
+        def v(self) -> None:
             pass
             pass
 
 
     class Grandchild3(Child3):
     class Grandchild3(Child3):

+ 5 - 2
tests/units/test_var.py

@@ -11,7 +11,10 @@ import reflex as rx
 from reflex.base import Base
 from reflex.base import Base
 from reflex.constants.base import REFLEX_VAR_CLOSING_TAG, REFLEX_VAR_OPENING_TAG
 from reflex.constants.base import REFLEX_VAR_CLOSING_TAG, REFLEX_VAR_OPENING_TAG
 from reflex.state import BaseState
 from reflex.state import BaseState
-from reflex.utils.exceptions import PrimitiveUnserializableToJSON
+from reflex.utils.exceptions import (
+    PrimitiveUnserializableToJSON,
+    UntypedComputedVarError,
+)
 from reflex.utils.imports import ImportVar
 from reflex.utils.imports import ImportVar
 from reflex.vars import VarData
 from reflex.vars import VarData
 from reflex.vars.base import (
 from reflex.vars.base import (
@@ -804,7 +807,7 @@ def test_shadow_computed_var_error(request: pytest.FixtureRequest, fixture: str)
         request: Fixture Request.
         request: Fixture Request.
         fixture: The state fixture.
         fixture: The state fixture.
     """
     """
-    with pytest.raises(NameError):
+    with pytest.raises(UntypedComputedVarError):
         state = request.getfixturevalue(fixture)
         state = request.getfixturevalue(fixture)
         state.var_without_annotation.foo
         state.var_without_annotation.foo
 
 

部分文件因为文件数量过多而无法显示