Skip to content
Draft
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
8 changes: 4 additions & 4 deletions packages/reflex-base/src/reflex_base/components/field.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,11 +110,11 @@ def _collect_inherited_fields(cls, bases: tuple[type, ...]) -> dict[str, Any]:

# Collect inherited fields from base classes
for base in bases[::-1]:
if hasattr(base, "_inherited_fields"):
inherited_fields.update(base._inherited_fields)
if (fields := getattr(base, "_inherited_fields", None)) is not None:
inherited_fields.update(fields)
for base in bases[::-1]:
if hasattr(base, "_own_fields"):
inherited_fields.update(base._own_fields)
if (fields := getattr(base, "_own_fields", None)) is not None:
inherited_fields.update(fields)

return inherited_fields

Expand Down
2 changes: 1 addition & 1 deletion packages/reflex-base/src/reflex_base/event/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -705,7 +705,7 @@ class EventChain(EventActionsMixin):

args_spec: Callable | Sequence[Callable] | None = dataclasses.field(default=None)

invocation: Var | None = dataclasses.field(default=None)
invocation: FunctionVar | None = dataclasses.field(default=None)

@classmethod
def create(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
"""Tailwind CSS configuration types for Reflex plugins."""

import dataclasses
from collections.abc import Mapping
from copy import deepcopy
from typing import Any, Literal, TypedDict

Expand Down Expand Up @@ -108,7 +107,7 @@ def tailwind_config_js_template(
imports = [
plugin["import"]
for plugin in plugins
if isinstance(plugin, Mapping) and "import" in plugin
if not isinstance(plugin, str) and "import" in plugin
Comment on lines -111 to +110

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i dont like this one because it's a runtime check. despite the static typing, if this plugin object is not a str, it could be anything else and indexing into it with a str would be invalid. hence, checking if it's explicitly a Mapping makes the in check and subsequent __getitem__ call safe.

what was the motivation for this change? i might be misreading it.

]

# Generate import statements for destructured imports
Expand All @@ -119,12 +118,12 @@ def tailwind_config_js_template(
# Generate plugin imports
plugin_imports = []
for i, plugin in enumerate(plugins, 1):
if isinstance(plugin, Mapping) and "call" not in plugin:
if isinstance(plugin, str):
plugin_imports.append(f"import plugin{i} from {json.dumps(plugin)};")
elif "call" not in plugin:
plugin_imports.append(
f"import plugin{i} from {json.dumps(plugin['name'])};"
)
elif not isinstance(plugin, Mapping):
plugin_imports.append(f"import plugin{i} from {json.dumps(plugin)};")

plugin_imports_lines = "\n".join(plugin_imports)

Expand All @@ -136,7 +135,7 @@ def tailwind_config_js_template(
# Generate plugin array
plugin_list = []
for i, plugin in enumerate(plugins, 1):
if isinstance(plugin, Mapping) and "call" in plugin:
if not isinstance(plugin, str) and "call" in plugin:
args_part = ""
if "args" in plugin:
args_part = json.dumps(plugin["args"])
Expand Down
30 changes: 20 additions & 10 deletions packages/reflex-base/src/reflex_base/vars/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -3516,12 +3516,22 @@ def __get__(

@overload
def __get__(
self: Field[list[V]]
| Field[set[V]]
| Field[list[V] | None]
| Field[set[V] | None],
instance: None,
owner: Any,
self: Field[list[V]], instance: None, owner: Any
) -> ArrayVar[Sequence[V]]: ...

@overload
def __get__(
self: Field[set[V]], instance: None, owner: Any
) -> ArrayVar[Sequence[V]]: ...

@overload
def __get__(
self: Field[list[V] | None], instance: None, owner: Any
) -> ArrayVar[Sequence[V]]: ...

@overload
def __get__(
self: Field[set[V] | None], instance: None, owner: Any
) -> ArrayVar[Sequence[V]]: ...

@overload
Expand Down Expand Up @@ -3667,11 +3677,11 @@ def __new__(
)

for base in bases[::-1]:
if hasattr(base, "__inherited_fields__"):
inherited_fields.update(base.__inherited_fields__)
if (fields := getattr(base, "__inherited_fields__", None)) is not None:
inherited_fields.update(fields)
for base in bases[::-1]:
if hasattr(base, "__own_fields__"):
inherited_fields.update(base.__own_fields__)
if (fields := getattr(base, "__own_fields__", None)) is not None:
inherited_fields.update(fields)

for key, value in [
(key, value)
Expand Down
15 changes: 7 additions & 8 deletions tests/units/test_prerequisites.py
Original file line number Diff line number Diff line change
Expand Up @@ -1339,14 +1339,12 @@ def test_extract_package_name():
assert js_runtimes._extract_package_name("@scope/pkg@1.2.3") == "@scope/pkg"


def test_cached_procedure():
def test_cached_procedure(tmp_path: Path):
call_count = 0

temp_file = tempfile.mktemp()
temp_file = tmp_path / "no_args_cache"

@cached_procedure(
cache_file_path=lambda: Path(temp_file), payload_fn=lambda: "constant"
)
@cached_procedure(cache_file_path=lambda: temp_file, payload_fn=lambda: "constant")
def _function_with_no_args():
nonlocal call_count
call_count += 1
Expand All @@ -1358,10 +1356,10 @@ def _function_with_no_args():

call_count = 0

another_temp_file = tempfile.mktemp()
another_temp_file = tmp_path / "some_args_cache"

@cached_procedure(
cache_file_path=lambda: Path(another_temp_file),
cache_file_path=lambda: another_temp_file,
payload_fn=lambda *args, **kwargs: f"{repr(args), repr(kwargs)}",
)
def _function_with_some_args(*args, **kwargs):
Expand All @@ -1380,7 +1378,8 @@ def _function_with_some_args(*args, **kwargs):
call_count = 0

@cached_procedure(
cache_file_path=lambda: Path(tempfile.mktemp()), payload_fn=lambda: "constant"
cache_file_path=lambda: tmp_path / f"fresh_{uuid.uuid4().hex}",
payload_fn=lambda: "constant",
)
def _function_with_no_args_fn():
nonlocal call_count
Expand Down
8 changes: 6 additions & 2 deletions tests/units/test_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -1535,11 +1535,14 @@ def dep_v(self) -> int:


@pytest.mark.parametrize("use_partial", [True, False])
def test_cached_var_depends_on_event_handler(use_partial: bool):
def test_cached_var_depends_on_event_handler(
use_partial: bool, monkeypatch: pytest.MonkeyPatch
):
"""A cached var that calls an event handler calculates deps correctly.

Args:
use_partial: if true, replace the EventHandler with functools.partial
monkeypatch: The pytest monkeypatch fixture.
"""
counter = 0

Expand All @@ -1557,7 +1560,8 @@ def cached_x_side_effect(self) -> int:
return counter

if use_partial:
HandlerState.handler = functools.partial(HandlerState.handler.fn) # pyright: ignore [reportFunctionMemberAccess]
handler_fn = HandlerState.event_handlers["handler"].fn
monkeypatch.setattr(HandlerState, "handler", functools.partial(handler_fn))
assert isinstance(HandlerState.handler, functools.partial)
else:
assert isinstance(HandlerState.handler, EventHandler)
Expand Down
Loading