Skip to content

v0.6.4

Latest
Compare
Choose a tag to compare
@masenf masenf released this 29 Oct 23:45
e471dc1

New Features

Make Var System Expandable

A new dispatch mechanism for converting python values into Var and LiteralVar subclasses. This allows component authors and downstream applications to better support custom frontend operations on Python values converted to Javascript values

See Example

This example allows for near drop-in support for working with SQLAlchemy DeclarativeBase models and will likely be included in a future release:

from collections.abc import Mapping, MutableSet, Sequence
from typing import TypeVar
import dataclasses
import sys

import reflex as rx
import sqlalchemy
import sqlalchemy.orm.exc
from sqlalchemy.orm import DeclarativeBase


class DeclarativeBaseVar(rx.vars.ObjectVar, python_types=DeclarativeBase):
    pass


@dataclasses.dataclass(
    eq=False,
    frozen=True,
    **{"slots": True} if sys.version_info >= (3, 10) else {},
)
class LiteralDeclarativeBaseVar(rx.vars.LiteralObjectVar, DeclarativeBaseVar):
    _var_value: DeclarativeBase | None = None


T = TypeVar("T")
K = TypeVar("K")
V = TypeVar("V")


@rx.serializer
def serialize_Sequence(s: Sequence[T] | MutableSet[T]) -> list[T]:
    return list(s)


@rx.serializer
def serialize_Mapping(m: Mapping[K, V]) -> dict[K, V]:
    return dict(m)


@rx.serializer
def serialize_DeclarativeBase(obj: DeclarativeBase) -> dict[str, str]:
    s = {}
    for attr in sqlalchemy.inspect(type(obj)).all_orm_descriptors.keys():
        try:
            s[attr] = getattr(obj, attr)
        except sqlalchemy.orm.exc.DetachedInstanceError:
            # This happens when the relationship was never loaded and the session is closed.
            continue
    return s

max-requests support to gunicorn (fixed memory leak)

This is a new configurable option in the rx.config but also now has default values.
gunicorn_max_requests - ( gunicorn / uvicorn )max requests per worker
Defaults value - 100
gunicorn_max_requests_jitter - (gunicorn only) variance in the max request limit. To prevent all workers restarting at same time
Defaults value - 25

What is max_requests?

max_requests is a the maximum number of requests a worker can serve before the manager will kill the worker and restart.

Why is this needed?

gunicorn workers don't release memory after a request. This can cause for a workers to hold on to more and more memory over time. Setting this flag means that after serving N requests the worker is killed, thus releasing the memory, and a new worker is spun up.

How to configure

rx.config(
    ...
     gunicorn_max_requests=50
    ...
)

Experimental Shiki Codeblock

rx._x.code_block(
"""
print("Original text")   # [!code --]
print("Replace original with this") # [!code ++]

name = "John Doe"  # [!code highlight]
""",
    language="python",
    theme="dracula",
    use_transformers=True,
    can_copy=True,
    show_line_numbers=True
)

dotenv support added

To use this feature, you must install python-dotenv separately from reflex.

import reflex as rx

config = rx.Config(
    app_name="mycoolapp",
    env_file=".env",
)

New rx.dynamic decorator

Unlike normal UI functions, this decorator allows UI code to directly access State instance values, Python-only APIs, and typical for and if statements.

See Example

We can implement a simple Reflex fiddle, that evaluates component strings into UI components and render them. This was previously difficult, as all UI had to compile into react code in the .web folder. This works by dynamically compiling a JavaScript module using in-window react.

import reflex as rx


class State(rx.State):
    component_str = "rx.button('login')"


@rx.dynamic
def evaluated_component(state: State):
    try:
        component = eval(
            state.component_str,
            {
                "rx": rx,
                "State": State,
            },
        )
    except Exception as e:
        return rx.text(f"Error: {e}")
    if not isinstance(component, rx.Component):
        return rx.text("Invalid component")
    return component


def index():
    return (
        rx.hstack(
            rx.text_area(
                value=State.component_str,
                on_change=State.set_component_str,
                height="100%",
                flex="1",
            ),
            rx.card(evaluated_component(), height="100%", flex="1"),
            height="100vh",
            padding="1rem",
            box_size="border-box",
        ),
    )

Improvements

Better Type Hinting for Built in Components

Other Improvements

Bug Fixes

Version Bumps

Other Changes

Full Changelog: v0.6.3.post1...v0.6.4