Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions packages/reflex-base/src/reflex_base/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ class BaseConfig:

env_file: str | None = None

state_auto_setters: bool | None = None
state_auto_setters: bool = False

show_built_with_reflex: bool | None = None

Expand Down Expand Up @@ -352,6 +352,21 @@ def _post_init(self, **kwargs):
if not self._skip_plugins_checks:
self._add_builtin_plugins()

# Warn if state_auto_setters is explicitly set.
if "state_auto_setters" in kwargs:
if kwargs["state_auto_setters"]:
reason = (
"auto setters will be removed; use explicit event handlers instead"
)
else:
reason = "state_auto_setters=False is already the default and the option will be removed"
console.deprecate(
feature_name="state_auto_setters",
reason=reason,
deprecation_version="0.9.0",
removal_version="1.0",
)

# Update default URLs if ports were set
kwargs.update(env_kwargs)
self._non_default_attributes = set(kwargs.keys())
Expand Down Expand Up @@ -381,7 +396,7 @@ def _normalize_disable_plugins(self):
feature_name="Passing strings to disable_plugins",
reason="pass Plugin classes directly instead, e.g. disable_plugins=[SitemapPlugin]",
deprecation_version="0.8.28",
removal_version="0.9.0",
removal_version="1.0",
)
try:
from reflex_base.environment import interpret_plugin_class_env
Expand Down
21 changes: 1 addition & 20 deletions packages/reflex-base/src/reflex_base/utils/compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@

import sys
from collections.abc import Mapping
from typing import TYPE_CHECKING, Any

if TYPE_CHECKING:
from pydantic.fields import FieldInfo
from typing import Any


async def windows_hot_reload_lifespan_hack():
Expand Down Expand Up @@ -51,19 +48,3 @@ def annotations_from_namespace(namespace: Mapping[str, Any]) -> dict[str, Any]:
if annotate := get_annotate_from_class_namespace(namespace):
return call_annotate_function(annotate, format=Format.FORWARDREF)
return namespace.get("__annotations__", {})


def sqlmodel_field_has_primary_key(field_info: "FieldInfo") -> bool:
"""Determines if a field is a primary.

Args:
field_info: a rx.model field

Returns:
If field_info is a primary key (Bool)
"""
if getattr(field_info, "primary_key", None) is True:
return True
if getattr(field_info, "sa_column", None) is None:
return False
return bool(getattr(field_info.sa_column, "primary_key", None)) # pyright: ignore[reportAttributeAccessIssue]
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
field,
)
from reflex_base.components.tags.tag import Tag
from reflex_base.utils import console
from reflex_base.utils.imports import ImportDict, ImportTypes, ImportVar
from reflex_base.vars.base import LiteralVar, Var, VarData
from reflex_base.vars.number import ternary_operation
Expand Down Expand Up @@ -242,14 +241,6 @@ def create(

# Update the base component map with the custom component map.
component_map = {**get_base_component_map(), **props.pop("component_map", {})}
if "codeblock" in component_map:
console.deprecate(
feature_name="'codeblock' in component_map",
reason="Use 'pre' instead of 'codeblock' to customize code block rendering in markdown",
deprecation_version="0.8.25",
removal_version="0.9.0",
)
component_map["pre"] = component_map.pop("codeblock")

# Get the markdown source.
src = children[0]
Expand Down
2 changes: 1 addition & 1 deletion pyi_hashes.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
"packages/reflex-components-dataeditor/src/reflex_components_dataeditor/dataeditor.pyi": "e10210239ce7dc18980e70eec19b9353",
"packages/reflex-components-gridjs/src/reflex_components_gridjs/datatable.pyi": "2a93782c63e82a6939411273fe2486d9",
"packages/reflex-components-lucide/src/reflex_components_lucide/icon.pyi": "f654cc9cb305712b485fcd676935c0c1",
"packages/reflex-components-markdown/src/reflex_components_markdown/markdown.pyi": "9c11bca2c4c5b722f55aba969f383e74",
"packages/reflex-components-markdown/src/reflex_components_markdown/markdown.pyi": "2d6efa2d5f2586a7036d606a24fb425d",
"packages/reflex-components-moment/src/reflex_components_moment/moment.pyi": "ad4b084d94e50311f761d69b3173e357",
"packages/reflex-components-plotly/src/reflex_components_plotly/plotly.pyi": "241b80584f3e029145e6e003d1c476f2",
"packages/reflex-components-radix/src/reflex_components_radix/__init__.pyi": "b2f485bfde4978047b7b944cf15d92cb",
Expand Down
21 changes: 0 additions & 21 deletions reflex/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -332,10 +332,6 @@ class App(MiddlewareMixin, LifespanMixin):

reset_style: bool = dataclasses.field(default=True)

overlay_component: Component | ComponentCallable | None = dataclasses.field(
default=None
)

app_wraps: dict[tuple[int, str], Callable[[bool], Component | None]] = (
dataclasses.field(
default_factory=lambda: {
Expand Down Expand Up @@ -1092,22 +1088,6 @@ def _add_overlay_to_component(

return Fragment.create(overlay_component, *children)

def _setup_overlay_component(self):
"""If a State is not used and no overlay_component is specified, do not render the connection modal."""
if self.overlay_component is None:
return
console.deprecate(
feature_name="overlay_component",
reason="Use `extra_app_wraps` to add the overlay component instead.",
deprecation_version="0.8.2",
removal_version="0.9.0",
)
overlay_component = self._generate_component(self.overlay_component)
for k, component in self._pages.items():
self._pages[k] = self._add_overlay_to_component(
component, overlay_component
)

def _setup_sticky_badge(self):
"""Add the sticky badge to the app."""
from reflex_base.components.component import memo
Expand Down Expand Up @@ -1285,7 +1265,6 @@ def get_compilation_time() -> str:
self._add_optional_endpoints()

self._validate_var_dependencies()
self._setup_overlay_component()

if config.show_built_with_reflex is None:
if (
Expand Down
2 changes: 1 addition & 1 deletion reflex/istate/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ def page(self) -> PageData:
feature_name="RouterData.page",
reason="Use RouterData.url instead",
deprecation_version="0.8.1",
removal_version="0.9.0",
removal_version="1.0",
)
return self._page

Expand Down
22 changes: 0 additions & 22 deletions reflex/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@
from reflex_base.utils import console
from reflex_base.utils.serializers import serializer

from reflex.utils.compat import sqlmodel_field_has_primary_key

if TYPE_CHECKING:
from typing import TypeVar

Expand Down Expand Up @@ -369,26 +367,6 @@ class Model(sqlmodel.SQLModel):
"extra": "allow",
}

@classmethod
def __pydantic_init_subclass__(cls):
"""Drop the default primary key field if any primary key field is defined."""
non_default_primary_key_fields = [
field_name
for field_name, field_info in cls.model_fields.items()
if field_name != "id" and sqlmodel_field_has_primary_key(field_info)
]
if non_default_primary_key_fields:
cls.model_fields.pop("id", None)
console.deprecate(
feature_name="Overriding default primary key",
reason=(
"Register sqlmodel.SQLModel classes with `@rx.ModelRegistry.register`"
),
deprecation_version="0.8.15",
removal_version="0.9.0",
)
super().__pydantic_init_subclass__()

@staticmethod
def create_all():
"""Create all the tables."""
Expand Down
48 changes: 1 addition & 47 deletions reflex/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,20 +222,8 @@ def __call__(self, *args: Any) -> EventSpec:
EventHandlerValueError: If the given Var name is not a str
NotImplementedError: If the setter for the given Var is async
"""
from reflex_base.config import get_config
from reflex_base.utils.exceptions import EventHandlerValueError

config = get_config()
if config.state_auto_setters is None and self.state is not None:
console.deprecate(
feature_name="state_auto_setters defaulting to True",
reason="The default value will be changed to False in a future release. Set state_auto_setters explicitly or define setters explicitly. "
f"Used {self.state.__name__}.setvar without defining it.",
deprecation_version="0.8.9",
removal_version="0.9.0",
dedupe=True,
)

if args:
if not isinstance(args[0], str):
msg = f"Var name must be passed as a string, got {args[0]!r}"
Expand Down Expand Up @@ -1073,7 +1061,7 @@ def _init_var(cls, name: str, prop: Var):
)
raise VarTypeError(msg)
cls._set_var(name, prop)
if cls.is_user_defined() and get_config().state_auto_setters is not False:
if cls.is_user_defined() and get_config().state_auto_setters is True:
cls._create_setter(name, prop)
cls._set_default_value(name, prop)

Expand Down Expand Up @@ -1170,29 +1158,8 @@ def _create_setter(cls, name: str, prop: Var):
name: The name of the var.
prop: The var to create a setter for.
"""
from reflex_base.config import get_config

config = get_config()
create_event_handler_kwargs = {}

if config.state_auto_setters is None:

class EventHandlerDeprecatedSetter(EventHandler):
def __call__(self, *args, **kwargs):
console.deprecate(
feature_name="state_auto_setters defaulting to True",
reason="The default value will be changed to False in a future release. Set state_auto_setters explicitly or define setters explicitly. "
f"Used {setter_name} in {cls.__name__} without defining it.",
deprecation_version="0.8.9",
removal_version="0.9.0",
dedupe=True,
)
return super().__call__(*args, **kwargs)

create_event_handler_kwargs["event_handler_cls"] = (
EventHandlerDeprecatedSetter
)

setter_name = Var._get_setter_name_for_name(name)
if setter_name not in cls.__dict__:
event_handler = cls._create_event_handler(
Expand Down Expand Up @@ -1874,19 +1841,6 @@ def get_value(self, key: str) -> Any:
Raises:
TypeError: If the key is not a string or MutableProxy.
"""
if isinstance(key, MutableProxy):
# Legacy behavior from v0.7.14: handle non-string keys with deprecation warning
from reflex_base.utils import console

console.deprecate(
feature_name="Non-string keys in get_value",
reason="Passing non-string keys to get_value is deprecated and will no longer be supported",
deprecation_version="0.8.0",
removal_version="0.9.0",
)

return key.__wrapped__

if isinstance(key, str):
if isinstance(val := getattr(self, key), MutableProxy):
return val.__wrapped__
Expand Down
65 changes: 6 additions & 59 deletions tests/units/test_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
from reflex_base.vars.base import computed_var
from reflex_components_core.base.bare import Bare
from reflex_components_core.base.fragment import Fragment
from reflex_components_core.core.cond import Cond
from reflex_components_radix.themes.typography.text import Text
from sqlalchemy.engine.base import Engine
from starlette.applications import Starlette
Expand All @@ -37,7 +36,7 @@

import reflex as rx
from reflex import AdminDash, constants
from reflex.app import App, ComponentCallable, default_overlay_component, upload
from reflex.app import App, ComponentCallable, upload
from reflex.environment import environment
from reflex.istate.manager.disk import StateManagerDisk
from reflex.istate.manager.memory import StateManagerMemory
Expand Down Expand Up @@ -523,6 +522,11 @@ async def test_dynamic_var_event(
clean_registration_context.register_base_state(test_state)
state = test_state() # pyright: ignore [reportCallIssue]
state.add_var("int_val", int, 0)

def set_int_val(self, value: int):
self.int_val = value

state._add_event_handler("set_int_val", set_int_val)
async with mock_base_state_event_processor as processor:
await processor.enqueue(
token,
Expand Down Expand Up @@ -1933,63 +1937,6 @@ async def test_process_events(
await mock_root_event_context.state_manager.close()


@pytest.mark.parametrize(
("state", "overlay_component", "exp_page_child"),
[
(None, default_overlay_component, Fragment),
(None, None, None),
(None, Text.create("foo"), Text),
(State, default_overlay_component, Fragment),
(State, None, None),
(State, Text.create("foo"), Text),
(State, lambda: Text.create("foo"), Text),
],
)
def test_overlay_component(
state: type[State] | None,
overlay_component: Component | ComponentCallable | None,
exp_page_child: type[Component] | None,
):
"""Test that the overlay component is set correctly.

Args:
state: The state class to pass to App.
overlay_component: The overlay_component to pass to App.
exp_page_child: The type of the expected child in the page fragment.
"""
app = App(_state=state, overlay_component=overlay_component)
app._setup_overlay_component()
if exp_page_child is None:
assert app.overlay_component is None
elif isinstance(exp_page_child, Fragment):
assert app.overlay_component is not None
generated_component = app._generate_component(app.overlay_component)
assert isinstance(generated_component, Fragment)
assert isinstance(
generated_component.children[0],
Cond, # ConnectionModal is a Cond under the hood
)
else:
assert app.overlay_component is not None
assert isinstance(
app._generate_component(app.overlay_component),
exp_page_child,
)

app.add_page(rx.box("Index"), route="/test")
# overlay components are wrapped during compile only
app._compile_page("test")
app._setup_overlay_component()
page = app._pages["test"]

if exp_page_child is not None:
assert len(page.children) == 4
children_types = (type(child) for child in page.children)
assert exp_page_child in children_types # pyright: ignore [reportOperatorIssue]
else:
assert len(page.children) == 3


@pytest.fixture
def compilable_app(tmp_path: Path) -> Generator[tuple[App, Path], None, None]:
"""Fixture for an app that can be compiled.
Expand Down
6 changes: 3 additions & 3 deletions tests/units/test_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class ChildModel(Model):


def test_default_primary_key(model_default_primary: Model):
"""Test that if a primary key is not defined a default is added.
"""Test that if no primary key is defined, an "id" field is added.

Args:
model_default_primary: Fixture.
Expand All @@ -59,12 +59,12 @@ def test_default_primary_key(model_default_primary: Model):


def test_custom_primary_key(model_custom_primary: Model):
"""Test that if a primary key is defined no default key is added.
"""Test that if a primary key is defined it is not overridden.

Args:
model_custom_primary: Fixture.
"""
assert "id" not in type(model_custom_primary).model_fields
assert "id" in type(model_custom_primary).model_fields


@pytest.mark.filterwarnings(
Expand Down
Loading
Loading