Compare commits
40 Commits
main
...
masenf/min
Author | SHA1 | Date | |
---|---|---|---|
![]() |
3d9cc5c957 | ||
![]() |
5ae1541aa9 | ||
![]() |
5c9839e0fe | ||
![]() |
0262143a4d | ||
![]() |
d8def13530 | ||
![]() |
0be2c3e810 | ||
![]() |
5840c0a24b | ||
![]() |
1e45a8e140 | ||
![]() |
a154a7d920 | ||
![]() |
a639f526da | ||
![]() |
3dd6e9c8ad | ||
![]() |
1ef54ecb93 | ||
![]() |
2e12feb120 | ||
![]() |
74c336f294 | ||
![]() |
6ce9471e6f | ||
![]() |
f94328f74f | ||
![]() |
46fefcf58c | ||
![]() |
24caf5fef1 | ||
![]() |
bcd0cf824d | ||
![]() |
84c14a189f | ||
![]() |
4116ab9f66 | ||
![]() |
d32604713c | ||
![]() |
db2b5b0320 | ||
![]() |
6eb808ca2c | ||
![]() |
4bbd988411 | ||
![]() |
f163d41563 | ||
![]() |
c26d626bf2 | ||
![]() |
79fc10957d | ||
![]() |
4e76e4d6ac | ||
![]() |
dadfb5663a | ||
![]() |
215a8343f4 | ||
![]() |
7287c3a167 | ||
![]() |
e9cedd2a92 | ||
![]() |
7bf15b4f44 | ||
![]() |
51aef9fd22 | ||
![]() |
8fc8fd9ec7 | ||
![]() |
bae98e80ed | ||
![]() |
1b0577a7e1 | ||
![]() |
0c406f4bac | ||
![]() |
673c488dc0 |
@ -23,6 +23,8 @@ export const clientStorage = {{ client_storage|json_dumps }}
|
|||||||
export const clientStorage = {}
|
export const clientStorage = {}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
export const main_state_name = "{{const.main_state_name}}"
|
||||||
|
export const update_vars_internal = "{{const.update_vars_internal}}"
|
||||||
{% if state_name %}
|
{% if state_name %}
|
||||||
export const state_name = "{{state_name}}"
|
export const state_name = "{{state_name}}"
|
||||||
|
|
||||||
|
@ -12,6 +12,8 @@ import {
|
|||||||
onLoadInternalEvent,
|
onLoadInternalEvent,
|
||||||
state_name,
|
state_name,
|
||||||
exception_state_name,
|
exception_state_name,
|
||||||
|
main_state_name,
|
||||||
|
update_vars_internal,
|
||||||
} from "$/utils/context.js";
|
} from "$/utils/context.js";
|
||||||
import debounce from "$/utils/helpers/debounce";
|
import debounce from "$/utils/helpers/debounce";
|
||||||
import throttle from "$/utils/helpers/throttle";
|
import throttle from "$/utils/helpers/throttle";
|
||||||
@ -117,7 +119,7 @@ export const isStateful = () => {
|
|||||||
if (event_queue.length === 0) {
|
if (event_queue.length === 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return event_queue.some((event) => event.name.startsWith("reflex___state"));
|
return event_queue.some(event => event.name.startsWith(main_state_name));
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -822,7 +824,7 @@ export const useEventLoop = (
|
|||||||
const vars = {};
|
const vars = {};
|
||||||
vars[storage_to_state_map[e.key]] = e.newValue;
|
vars[storage_to_state_map[e.key]] = e.newValue;
|
||||||
const event = Event(
|
const event = Event(
|
||||||
`${state_name}.reflex___state____update_vars_internal_state.update_vars_internal`,
|
`${state_name}.${update_vars_internal}`,
|
||||||
{ vars: vars }
|
{ vars: vars }
|
||||||
);
|
);
|
||||||
addEvents([event], e);
|
addEvents([event], e);
|
||||||
@ -836,7 +838,7 @@ export const useEventLoop = (
|
|||||||
// Route after the initial page hydration.
|
// Route after the initial page hydration.
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const change_start = () => {
|
const change_start = () => {
|
||||||
const main_state_dispatch = dispatch["reflex___state____state"];
|
const main_state_dispatch = dispatch[main_state_name];
|
||||||
if (main_state_dispatch !== undefined) {
|
if (main_state_dispatch !== undefined) {
|
||||||
main_state_dispatch({ is_hydrated: false });
|
main_state_dispatch({ is_hydrated: false });
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ def _compile_document_root(root: Component) -> str:
|
|||||||
Returns:
|
Returns:
|
||||||
The compiled document root.
|
The compiled document root.
|
||||||
"""
|
"""
|
||||||
return templates.DOCUMENT_ROOT.render(
|
return templates.document_root().render(
|
||||||
imports=utils.compile_imports(root._get_all_imports()),
|
imports=utils.compile_imports(root._get_all_imports()),
|
||||||
document=root.render(),
|
document=root.render(),
|
||||||
)
|
)
|
||||||
@ -72,7 +72,7 @@ def _compile_app(app_root: Component) -> str:
|
|||||||
("utils_state", f"$/{constants.Dirs.UTILS}/state"),
|
("utils_state", f"$/{constants.Dirs.UTILS}/state"),
|
||||||
]
|
]
|
||||||
|
|
||||||
return templates.APP_ROOT.render(
|
return templates.app_root().render(
|
||||||
imports=utils.compile_imports(app_root._get_all_imports()),
|
imports=utils.compile_imports(app_root._get_all_imports()),
|
||||||
custom_codes=app_root._get_all_custom_code(),
|
custom_codes=app_root._get_all_custom_code(),
|
||||||
hooks={**app_root._get_all_hooks_internal(), **app_root._get_all_hooks()},
|
hooks={**app_root._get_all_hooks_internal(), **app_root._get_all_hooks()},
|
||||||
@ -90,7 +90,7 @@ def _compile_theme(theme: str) -> str:
|
|||||||
Returns:
|
Returns:
|
||||||
The compiled theme.
|
The compiled theme.
|
||||||
"""
|
"""
|
||||||
return templates.THEME.render(theme=theme)
|
return templates.theme().render(theme=theme)
|
||||||
|
|
||||||
|
|
||||||
def _compile_contexts(state: Optional[Type[BaseState]], theme: Component | None) -> str:
|
def _compile_contexts(state: Optional[Type[BaseState]], theme: Component | None) -> str:
|
||||||
@ -109,7 +109,7 @@ def _compile_contexts(state: Optional[Type[BaseState]], theme: Component | None)
|
|||||||
|
|
||||||
last_compiled_time = str(datetime.now())
|
last_compiled_time = str(datetime.now())
|
||||||
return (
|
return (
|
||||||
templates.CONTEXT.render(
|
templates.context().render(
|
||||||
initial_state=utils.compile_state(state),
|
initial_state=utils.compile_state(state),
|
||||||
state_name=state.get_name(),
|
state_name=state.get_name(),
|
||||||
client_storage=utils.compile_client_storage(state),
|
client_storage=utils.compile_client_storage(state),
|
||||||
@ -118,7 +118,7 @@ def _compile_contexts(state: Optional[Type[BaseState]], theme: Component | None)
|
|||||||
default_color_mode=appearance,
|
default_color_mode=appearance,
|
||||||
)
|
)
|
||||||
if state
|
if state
|
||||||
else templates.CONTEXT.render(
|
else templates.context().render(
|
||||||
is_dev_mode=not is_prod_mode(),
|
is_dev_mode=not is_prod_mode(),
|
||||||
default_color_mode=appearance,
|
default_color_mode=appearance,
|
||||||
last_compiled_time=last_compiled_time,
|
last_compiled_time=last_compiled_time,
|
||||||
@ -145,7 +145,7 @@ def _compile_page(
|
|||||||
# Compile the code to render the component.
|
# Compile the code to render the component.
|
||||||
kwargs = {"state_name": state.get_name()} if state is not None else {}
|
kwargs = {"state_name": state.get_name()} if state is not None else {}
|
||||||
|
|
||||||
return templates.PAGE.render(
|
return templates.page().render(
|
||||||
imports=imports,
|
imports=imports,
|
||||||
dynamic_imports=component._get_all_dynamic_imports(),
|
dynamic_imports=component._get_all_dynamic_imports(),
|
||||||
custom_codes=component._get_all_custom_code(),
|
custom_codes=component._get_all_custom_code(),
|
||||||
@ -201,7 +201,7 @@ def _compile_root_stylesheet(stylesheets: list[str]) -> str:
|
|||||||
)
|
)
|
||||||
stylesheet = f"../{constants.Dirs.PUBLIC}/{stylesheet.strip('/')}"
|
stylesheet = f"../{constants.Dirs.PUBLIC}/{stylesheet.strip('/')}"
|
||||||
sheets.append(stylesheet) if stylesheet not in sheets else None
|
sheets.append(stylesheet) if stylesheet not in sheets else None
|
||||||
return templates.STYLE.render(stylesheets=sheets)
|
return templates.style().render(stylesheets=sheets)
|
||||||
|
|
||||||
|
|
||||||
def _compile_component(component: Component | StatefulComponent) -> str:
|
def _compile_component(component: Component | StatefulComponent) -> str:
|
||||||
@ -213,7 +213,7 @@ def _compile_component(component: Component | StatefulComponent) -> str:
|
|||||||
Returns:
|
Returns:
|
||||||
The compiled component.
|
The compiled component.
|
||||||
"""
|
"""
|
||||||
return templates.COMPONENT.render(component=component)
|
return templates.component().render(component=component)
|
||||||
|
|
||||||
|
|
||||||
def _compile_components(
|
def _compile_components(
|
||||||
@ -241,7 +241,7 @@ def _compile_components(
|
|||||||
|
|
||||||
# Compile the components page.
|
# Compile the components page.
|
||||||
return (
|
return (
|
||||||
templates.COMPONENTS.render(
|
templates.components().render(
|
||||||
imports=utils.compile_imports(imports),
|
imports=utils.compile_imports(imports),
|
||||||
components=component_renders,
|
components=component_renders,
|
||||||
),
|
),
|
||||||
@ -319,7 +319,7 @@ def _compile_stateful_components(
|
|||||||
f"$/{constants.Dirs.UTILS}/{constants.PageNames.STATEFUL_COMPONENTS}", None
|
f"$/{constants.Dirs.UTILS}/{constants.PageNames.STATEFUL_COMPONENTS}", None
|
||||||
)
|
)
|
||||||
|
|
||||||
return templates.STATEFUL_COMPONENTS.render(
|
return templates.stateful_components().render(
|
||||||
imports=utils.compile_imports(all_imports),
|
imports=utils.compile_imports(all_imports),
|
||||||
memoized_code="\n".join(rendered_components),
|
memoized_code="\n".join(rendered_components),
|
||||||
)
|
)
|
||||||
@ -336,7 +336,7 @@ def _compile_tailwind(
|
|||||||
Returns:
|
Returns:
|
||||||
The compiled Tailwind config.
|
The compiled Tailwind config.
|
||||||
"""
|
"""
|
||||||
return templates.TAILWIND_CONFIG.render(
|
return templates.tailwind_config().render(
|
||||||
**config,
|
**config,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -11,6 +11,13 @@ class ReflexJinjaEnvironment(Environment):
|
|||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
"""Set default environment."""
|
"""Set default environment."""
|
||||||
|
from reflex.state import (
|
||||||
|
FrontendEventExceptionState,
|
||||||
|
OnLoadInternalState,
|
||||||
|
State,
|
||||||
|
UpdateVarsInternalState,
|
||||||
|
)
|
||||||
|
|
||||||
extensions = ["jinja2.ext.debug"]
|
extensions = ["jinja2.ext.debug"]
|
||||||
super().__init__(
|
super().__init__(
|
||||||
extensions=extensions,
|
extensions=extensions,
|
||||||
@ -42,9 +49,10 @@ class ReflexJinjaEnvironment(Environment):
|
|||||||
"set_color_mode": constants.ColorMode.SET,
|
"set_color_mode": constants.ColorMode.SET,
|
||||||
"use_color_mode": constants.ColorMode.USE,
|
"use_color_mode": constants.ColorMode.USE,
|
||||||
"hydrate": constants.CompileVars.HYDRATE,
|
"hydrate": constants.CompileVars.HYDRATE,
|
||||||
"on_load_internal": constants.CompileVars.ON_LOAD_INTERNAL,
|
"main_state_name": State.get_name(),
|
||||||
"update_vars_internal": constants.CompileVars.UPDATE_VARS_INTERNAL,
|
"on_load_internal": f"{OnLoadInternalState.get_name()}.on_load_internal",
|
||||||
"frontend_exception_state": constants.CompileVars.FRONTEND_EXCEPTION_STATE_FULL,
|
"update_vars_internal": f"{UpdateVarsInternalState.get_name()}.update_vars_internal",
|
||||||
|
"frontend_exception_state": FrontendEventExceptionState.get_full_name(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -60,61 +68,172 @@ def get_template(name: str) -> Template:
|
|||||||
return ReflexJinjaEnvironment().get_template(name=name)
|
return ReflexJinjaEnvironment().get_template(name=name)
|
||||||
|
|
||||||
|
|
||||||
# Template for the Reflex config file.
|
def rxconfig():
|
||||||
RXCONFIG = get_template("app/rxconfig.py.jinja2")
|
"""Template for the Reflex config file.
|
||||||
|
|
||||||
# Code to render a NextJS Document root.
|
Returns:
|
||||||
DOCUMENT_ROOT = get_template("web/pages/_document.js.jinja2")
|
Template: The template for the Reflex config file.
|
||||||
|
"""
|
||||||
|
return get_template("app/rxconfig.py.jinja2")
|
||||||
|
|
||||||
# Code to render NextJS App root.
|
|
||||||
APP_ROOT = get_template("web/pages/_app.js.jinja2")
|
|
||||||
|
|
||||||
# Template for the theme file.
|
def document_root():
|
||||||
THEME = get_template("web/utils/theme.js.jinja2")
|
"""Code to render a NextJS Document root.
|
||||||
|
|
||||||
# Template for the context file.
|
Returns:
|
||||||
CONTEXT = get_template("web/utils/context.js.jinja2")
|
Template: The template for the NextJS Document root.
|
||||||
|
"""
|
||||||
|
return get_template("web/pages/_document.js.jinja2")
|
||||||
|
|
||||||
# Template for Tailwind config.
|
|
||||||
TAILWIND_CONFIG = get_template("web/tailwind.config.js.jinja2")
|
|
||||||
|
|
||||||
# Template to render a component tag.
|
def app_root():
|
||||||
COMPONENT = get_template("web/pages/component.js.jinja2")
|
"""Code to render NextJS App root.
|
||||||
|
|
||||||
# Code to render a single NextJS page.
|
Returns:
|
||||||
PAGE = get_template("web/pages/index.js.jinja2")
|
Template: The template for the NextJS App root.
|
||||||
|
"""
|
||||||
|
return get_template("web/pages/_app.js.jinja2")
|
||||||
|
|
||||||
# Code to render the custom components page.
|
|
||||||
COMPONENTS = get_template("web/pages/custom_component.js.jinja2")
|
|
||||||
|
|
||||||
# Code to render Component instances as part of StatefulComponent
|
def theme():
|
||||||
STATEFUL_COMPONENT = get_template("web/pages/stateful_component.js.jinja2")
|
"""Template for the theme file.
|
||||||
|
|
||||||
# Code to render StatefulComponent to an external file to be shared
|
Returns:
|
||||||
STATEFUL_COMPONENTS = get_template("web/pages/stateful_components.js.jinja2")
|
Template: The template for the theme file.
|
||||||
|
"""
|
||||||
|
return get_template("web/utils/theme.js.jinja2")
|
||||||
|
|
||||||
# Sitemap config file.
|
|
||||||
SITEMAP_CONFIG = "module.exports = {config}".format
|
|
||||||
|
|
||||||
# Code to render the root stylesheet.
|
def context():
|
||||||
STYLE = get_template("web/styles/styles.css.jinja2")
|
"""Template for the context file.
|
||||||
|
|
||||||
# Code that generate the package json file
|
Returns:
|
||||||
PACKAGE_JSON = get_template("web/package.json.jinja2")
|
Template: The template for the context file.
|
||||||
|
"""
|
||||||
|
return get_template("web/utils/context.js.jinja2")
|
||||||
|
|
||||||
# Code that generate the pyproject.toml file for custom components.
|
|
||||||
CUSTOM_COMPONENTS_PYPROJECT_TOML = get_template(
|
|
||||||
"custom_components/pyproject.toml.jinja2"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Code that generates the README file for custom components.
|
def tailwind_config():
|
||||||
CUSTOM_COMPONENTS_README = get_template("custom_components/README.md.jinja2")
|
"""Template for Tailwind config.
|
||||||
|
|
||||||
# Code that generates the source file for custom components.
|
Returns:
|
||||||
CUSTOM_COMPONENTS_SOURCE = get_template("custom_components/src.py.jinja2")
|
Template: The template for the Tailwind config
|
||||||
|
"""
|
||||||
|
return get_template("web/tailwind.config.js.jinja2")
|
||||||
|
|
||||||
# Code that generates the init file for custom components.
|
|
||||||
CUSTOM_COMPONENTS_INIT_FILE = get_template("custom_components/__init__.py.jinja2")
|
|
||||||
|
|
||||||
# Code that generates the demo app main py file for testing custom components.
|
def component():
|
||||||
CUSTOM_COMPONENTS_DEMO_APP = get_template("custom_components/demo_app.py.jinja2")
|
"""Template to render a component tag.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Template: The template for the component tag.
|
||||||
|
"""
|
||||||
|
return get_template("web/pages/component.js.jinja2")
|
||||||
|
|
||||||
|
|
||||||
|
def page():
|
||||||
|
"""Code to render a single NextJS page.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Template: The template for the NextJS page.
|
||||||
|
"""
|
||||||
|
return get_template("web/pages/index.js.jinja2")
|
||||||
|
|
||||||
|
|
||||||
|
def components():
|
||||||
|
"""Code to render the custom components page.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Template: The template for the custom components page.
|
||||||
|
"""
|
||||||
|
return get_template("web/pages/custom_component.js.jinja2")
|
||||||
|
|
||||||
|
|
||||||
|
def stateful_component():
|
||||||
|
"""Code to render Component instances as part of StatefulComponent.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Template: The template for the StatefulComponent.
|
||||||
|
"""
|
||||||
|
return get_template("web/pages/stateful_component.js.jinja2")
|
||||||
|
|
||||||
|
|
||||||
|
def stateful_components():
|
||||||
|
"""Code to render StatefulComponent to an external file to be shared.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Template: The template for the StatefulComponent.
|
||||||
|
"""
|
||||||
|
return get_template("web/pages/stateful_components.js.jinja2")
|
||||||
|
|
||||||
|
|
||||||
|
def sitemap_config():
|
||||||
|
"""Sitemap config file.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Template: The template for the sitemap config file.
|
||||||
|
"""
|
||||||
|
return "module.exports = {config}".format
|
||||||
|
|
||||||
|
|
||||||
|
def style():
|
||||||
|
"""Code to render the root stylesheet.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Template: The template for the root stylesheet
|
||||||
|
"""
|
||||||
|
return get_template("web/styles/styles.css.jinja2")
|
||||||
|
|
||||||
|
|
||||||
|
def package_json():
|
||||||
|
"""Code that generate the package json file.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Template: The template for the package json file
|
||||||
|
"""
|
||||||
|
return get_template("web/package.json.jinja2")
|
||||||
|
|
||||||
|
|
||||||
|
def custom_components_pyproject_toml():
|
||||||
|
"""Code that generate the pyproject.toml file for custom components.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Template: The template for the pyproject.toml file
|
||||||
|
"""
|
||||||
|
return get_template("custom_components/pyproject.toml.jinja2")
|
||||||
|
|
||||||
|
|
||||||
|
def custom_components_readme():
|
||||||
|
"""Code that generates the README file for custom components.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Template: The template for the README file
|
||||||
|
"""
|
||||||
|
return get_template("custom_components/README.md.jinja2")
|
||||||
|
|
||||||
|
|
||||||
|
def custom_components_source():
|
||||||
|
"""Code that generates the source file for custom components.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Template: The template for the source file
|
||||||
|
"""
|
||||||
|
return get_template("custom_components/src.py.jinja2")
|
||||||
|
|
||||||
|
|
||||||
|
def custom_components_init():
|
||||||
|
"""Code that generates the init file for custom components.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Template: The template for the init file
|
||||||
|
"""
|
||||||
|
return get_template("custom_components/__init__.py.jinja2")
|
||||||
|
|
||||||
|
|
||||||
|
def custom_components_demo_app():
|
||||||
|
"""Code that generates the demo app main py file for testing custom components.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Template: The template for the demo app main py file
|
||||||
|
"""
|
||||||
|
return get_template("custom_components/demo_app.py.jinja2")
|
||||||
|
@ -25,7 +25,7 @@ from typing import (
|
|||||||
|
|
||||||
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
|
||||||
from reflex.components.core.breakpoints import Breakpoints
|
from reflex.components.core.breakpoints import Breakpoints
|
||||||
from reflex.components.dynamic import load_dynamic_serializer
|
from reflex.components.dynamic import load_dynamic_serializer
|
||||||
from reflex.components.tags import Tag
|
from reflex.components.tags import Tag
|
||||||
@ -2162,7 +2162,7 @@ class StatefulComponent(BaseComponent):
|
|||||||
component.event_triggers[event_trigger] = memo_trigger
|
component.event_triggers[event_trigger] = memo_trigger
|
||||||
|
|
||||||
# Render the code for this component and hooks.
|
# Render the code for this component and hooks.
|
||||||
return STATEFUL_COMPONENT.render(
|
return stateful_component().render(
|
||||||
tag_name=tag_name,
|
tag_name=tag_name,
|
||||||
memo_trigger_hooks=memo_trigger_hooks,
|
memo_trigger_hooks=memo_trigger_hooks,
|
||||||
component=component,
|
component=component,
|
||||||
|
@ -80,7 +80,7 @@ def load_dynamic_serializer():
|
|||||||
)
|
)
|
||||||
|
|
||||||
rendered_components[
|
rendered_components[
|
||||||
templates.STATEFUL_COMPONENT.render(
|
templates.stateful_component().render(
|
||||||
tag_name="MySSRComponent",
|
tag_name="MySSRComponent",
|
||||||
memo_trigger_hooks=[],
|
memo_trigger_hooks=[],
|
||||||
component=component,
|
component=component,
|
||||||
@ -101,10 +101,14 @@ def load_dynamic_serializer():
|
|||||||
else:
|
else:
|
||||||
imports[lib] = names
|
imports[lib] = names
|
||||||
|
|
||||||
module_code_lines = templates.STATEFUL_COMPONENTS.render(
|
module_code_lines = (
|
||||||
imports=utils.compile_imports(imports),
|
templates.stateful_components()
|
||||||
memoized_code="\n".join(rendered_components),
|
.render(
|
||||||
).splitlines()[1:]
|
imports=utils.compile_imports(imports),
|
||||||
|
memoized_code="\n".join(rendered_components),
|
||||||
|
)
|
||||||
|
.splitlines()[1:]
|
||||||
|
)
|
||||||
|
|
||||||
# Rewrite imports from `/` to destructure from window
|
# Rewrite imports from `/` to destructure from window
|
||||||
for ix, line in enumerate(module_code_lines[:]):
|
for ix, line in enumerate(module_code_lines[:]):
|
||||||
|
110
reflex/config.py
110
reflex/config.py
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import dataclasses
|
|
||||||
import enum
|
import enum
|
||||||
import importlib
|
import importlib
|
||||||
import inspect
|
import inspect
|
||||||
@ -15,6 +14,7 @@ from pathlib import Path
|
|||||||
from typing import (
|
from typing import (
|
||||||
TYPE_CHECKING,
|
TYPE_CHECKING,
|
||||||
Any,
|
Any,
|
||||||
|
Callable,
|
||||||
Dict,
|
Dict,
|
||||||
Generic,
|
Generic,
|
||||||
List,
|
List,
|
||||||
@ -149,28 +149,6 @@ class DBConfig(Base):
|
|||||||
return f"{self.engine}://{path}/{self.database}"
|
return f"{self.engine}://{path}/{self.database}"
|
||||||
|
|
||||||
|
|
||||||
def get_default_value_for_field(field: dataclasses.Field) -> Any:
|
|
||||||
"""Get the default value for a field.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
field: The field.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
The default value.
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
ValueError: If no default value is found.
|
|
||||||
"""
|
|
||||||
if field.default != dataclasses.MISSING:
|
|
||||||
return field.default
|
|
||||||
elif field.default_factory != dataclasses.MISSING:
|
|
||||||
return field.default_factory()
|
|
||||||
else:
|
|
||||||
raise ValueError(
|
|
||||||
f"Missing value for environment variable {field.name} and no default value found"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# TODO: Change all interpret_.* signatures to value: str, field: dataclasses.Field once we migrate rx.Config to dataclasses
|
# TODO: Change all interpret_.* signatures to value: str, field: dataclasses.Field once we migrate rx.Config to dataclasses
|
||||||
def interpret_boolean_env(value: str, field_name: str) -> bool:
|
def interpret_boolean_env(value: str, field_name: str) -> bool:
|
||||||
"""Interpret a boolean environment variable value.
|
"""Interpret a boolean environment variable value.
|
||||||
@ -314,26 +292,47 @@ def interpret_env_var_value(
|
|||||||
|
|
||||||
T = TypeVar("T")
|
T = TypeVar("T")
|
||||||
|
|
||||||
|
ENV_VAR_DEFAULT_FACTORY = Callable[[], T]
|
||||||
|
|
||||||
|
|
||||||
class EnvVar(Generic[T]):
|
class EnvVar(Generic[T]):
|
||||||
"""Environment variable."""
|
"""Environment variable."""
|
||||||
|
|
||||||
name: str
|
name: str
|
||||||
default: Any
|
default: Any
|
||||||
|
default_factory: Optional[ENV_VAR_DEFAULT_FACTORY]
|
||||||
type_: T
|
type_: T
|
||||||
|
|
||||||
def __init__(self, name: str, default: Any, type_: T) -> None:
|
def __init__(
|
||||||
|
self,
|
||||||
|
name: str,
|
||||||
|
default: Any,
|
||||||
|
default_factory: Optional[ENV_VAR_DEFAULT_FACTORY],
|
||||||
|
type_: T,
|
||||||
|
) -> None:
|
||||||
"""Initialize the environment variable.
|
"""Initialize the environment variable.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
name: The environment variable name.
|
name: The environment variable name.
|
||||||
default: The default value.
|
default: The default value.
|
||||||
|
default_factory: The default factory.
|
||||||
type_: The type of the value.
|
type_: The type of the value.
|
||||||
"""
|
"""
|
||||||
self.name = name
|
self.name = name
|
||||||
self.default = default
|
self.default = default
|
||||||
|
self.default_factory = default_factory
|
||||||
self.type_ = type_
|
self.type_ = type_
|
||||||
|
|
||||||
|
def get_default(self) -> T:
|
||||||
|
"""Get the default value.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The default value.
|
||||||
|
"""
|
||||||
|
if self.default_factory is not None:
|
||||||
|
return self.default_factory()
|
||||||
|
return self.default
|
||||||
|
|
||||||
def interpret(self, value: str) -> T:
|
def interpret(self, value: str) -> T:
|
||||||
"""Interpret the environment variable value.
|
"""Interpret the environment variable value.
|
||||||
|
|
||||||
@ -373,7 +372,7 @@ class EnvVar(Generic[T]):
|
|||||||
env_value = self.getenv()
|
env_value = self.getenv()
|
||||||
if env_value is not None:
|
if env_value is not None:
|
||||||
return env_value
|
return env_value
|
||||||
return self.default
|
return self.get_default()
|
||||||
|
|
||||||
def set(self, value: T | None) -> None:
|
def set(self, value: T | None) -> None:
|
||||||
"""Set the environment variable. None unsets the variable.
|
"""Set the environment variable. None unsets the variable.
|
||||||
@ -394,16 +393,24 @@ class env_var: # type: ignore
|
|||||||
|
|
||||||
name: str
|
name: str
|
||||||
default: Any
|
default: Any
|
||||||
|
default_factory: Optional[ENV_VAR_DEFAULT_FACTORY]
|
||||||
internal: bool = False
|
internal: bool = False
|
||||||
|
|
||||||
def __init__(self, default: Any, internal: bool = False) -> None:
|
def __init__(
|
||||||
|
self,
|
||||||
|
default: Any = None,
|
||||||
|
default_factory: Optional[ENV_VAR_DEFAULT_FACTORY] = None,
|
||||||
|
internal: bool = False,
|
||||||
|
) -> None:
|
||||||
"""Initialize the descriptor.
|
"""Initialize the descriptor.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
default: The default value.
|
default: The default value.
|
||||||
|
default_factory: The default factory.
|
||||||
internal: Whether the environment variable is reflex internal.
|
internal: Whether the environment variable is reflex internal.
|
||||||
"""
|
"""
|
||||||
self.default = default
|
self.default = default
|
||||||
|
self.default_factory = default_factory
|
||||||
self.internal = internal
|
self.internal = internal
|
||||||
|
|
||||||
def __set_name__(self, owner, name):
|
def __set_name__(self, owner, name):
|
||||||
@ -429,22 +436,30 @@ class env_var: # type: ignore
|
|||||||
env_name = self.name
|
env_name = self.name
|
||||||
if self.internal:
|
if self.internal:
|
||||||
env_name = f"__{env_name}"
|
env_name = f"__{env_name}"
|
||||||
return EnvVar(name=env_name, default=self.default, type_=type_)
|
return EnvVar(
|
||||||
|
name=env_name,
|
||||||
|
default=self.default,
|
||||||
|
type_=type_,
|
||||||
|
default_factory=self.default_factory,
|
||||||
|
)
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
def __new__(
|
||||||
|
cls,
|
||||||
|
default: Optional[T] = None,
|
||||||
|
default_factory: Optional[ENV_VAR_DEFAULT_FACTORY[T]] = None,
|
||||||
|
internal: bool = False,
|
||||||
|
) -> EnvVar[T]:
|
||||||
|
"""Create a new EnvVar instance.
|
||||||
|
|
||||||
def env_var(default, internal=False) -> EnvVar:
|
Args:
|
||||||
"""Typing helper for the env_var descriptor.
|
cls: The class.
|
||||||
|
default: The default value.
|
||||||
Args:
|
default_factory: The default factory.
|
||||||
default: The default value.
|
internal: Whether the environment variable is reflex internal.
|
||||||
internal: Whether the environment variable is reflex internal.
|
"""
|
||||||
|
...
|
||||||
Returns:
|
|
||||||
The EnvVar instance.
|
|
||||||
"""
|
|
||||||
return default
|
|
||||||
|
|
||||||
|
|
||||||
class PathExistsFlag:
|
class PathExistsFlag:
|
||||||
@ -465,6 +480,16 @@ class PerformanceMode(enum.Enum):
|
|||||||
class EnvironmentVariables:
|
class EnvironmentVariables:
|
||||||
"""Environment variables class to instantiate environment variables."""
|
"""Environment variables class to instantiate environment variables."""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
"""Initialize the environment variables.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
NotImplementedError: Always.
|
||||||
|
"""
|
||||||
|
raise NotImplementedError(
|
||||||
|
f"{type(self).__name__} is a class singleton and not meant to be instantiated."
|
||||||
|
)
|
||||||
|
|
||||||
# Whether to use npm over bun to install frontend packages.
|
# Whether to use npm over bun to install frontend packages.
|
||||||
REFLEX_USE_NPM: EnvVar[bool] = env_var(False)
|
REFLEX_USE_NPM: EnvVar[bool] = env_var(False)
|
||||||
|
|
||||||
@ -564,8 +589,13 @@ class EnvironmentVariables:
|
|||||||
# The maximum size of the reflex state in kilobytes.
|
# The maximum size of the reflex state in kilobytes.
|
||||||
REFLEX_STATE_SIZE_LIMIT: EnvVar[int] = env_var(1000)
|
REFLEX_STATE_SIZE_LIMIT: EnvVar[int] = env_var(1000)
|
||||||
|
|
||||||
|
# Whether to minify state names. Default to true in prod mode and false otherwise.
|
||||||
|
REFLEX_MINIFY_STATES: EnvVar[Optional[bool]] = env_var(
|
||||||
|
default_factory=lambda: environment.REFLEX_ENV_MODE.get() == constants.Env.PROD
|
||||||
|
)
|
||||||
|
|
||||||
environment = EnvironmentVariables()
|
|
||||||
|
environment = EnvironmentVariables
|
||||||
|
|
||||||
|
|
||||||
class Config(Base):
|
class Config(Base):
|
||||||
|
@ -61,18 +61,6 @@ class CompileVars(SimpleNamespace):
|
|||||||
CONNECT_ERROR = "connectErrors"
|
CONNECT_ERROR = "connectErrors"
|
||||||
# The name of the function for converting a dict to an event.
|
# The name of the function for converting a dict to an event.
|
||||||
TO_EVENT = "Event"
|
TO_EVENT = "Event"
|
||||||
# The name of the internal on_load event.
|
|
||||||
ON_LOAD_INTERNAL = "reflex___state____on_load_internal_state.on_load_internal"
|
|
||||||
# The name of the internal event to update generic state vars.
|
|
||||||
UPDATE_VARS_INTERNAL = (
|
|
||||||
"reflex___state____update_vars_internal_state.update_vars_internal"
|
|
||||||
)
|
|
||||||
# The name of the frontend event exception state
|
|
||||||
FRONTEND_EXCEPTION_STATE = "reflex___state____frontend_event_exception_state"
|
|
||||||
# The full name of the frontend exception state
|
|
||||||
FRONTEND_EXCEPTION_STATE_FULL = (
|
|
||||||
f"reflex___state____state.{FRONTEND_EXCEPTION_STATE}"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class PageNames(SimpleNamespace):
|
class PageNames(SimpleNamespace):
|
||||||
|
@ -65,7 +65,7 @@ def _create_package_config(module_name: str, package_name: str):
|
|||||||
|
|
||||||
pyproject = Path(CustomComponents.PYPROJECT_TOML)
|
pyproject = Path(CustomComponents.PYPROJECT_TOML)
|
||||||
pyproject.write_text(
|
pyproject.write_text(
|
||||||
templates.CUSTOM_COMPONENTS_PYPROJECT_TOML.render(
|
templates.custom_components_pyproject_toml().render(
|
||||||
module_name=module_name,
|
module_name=module_name,
|
||||||
package_name=package_name,
|
package_name=package_name,
|
||||||
reflex_version=constants.Reflex.VERSION,
|
reflex_version=constants.Reflex.VERSION,
|
||||||
@ -106,7 +106,7 @@ def _create_readme(module_name: str, package_name: str):
|
|||||||
|
|
||||||
readme = Path(CustomComponents.PACKAGE_README)
|
readme = Path(CustomComponents.PACKAGE_README)
|
||||||
readme.write_text(
|
readme.write_text(
|
||||||
templates.CUSTOM_COMPONENTS_README.render(
|
templates.custom_components_readme().render(
|
||||||
module_name=module_name,
|
module_name=module_name,
|
||||||
package_name=package_name,
|
package_name=package_name,
|
||||||
)
|
)
|
||||||
@ -129,14 +129,14 @@ def _write_source_and_init_py(
|
|||||||
|
|
||||||
module_path = custom_component_src_dir / f"{module_name}.py"
|
module_path = custom_component_src_dir / f"{module_name}.py"
|
||||||
module_path.write_text(
|
module_path.write_text(
|
||||||
templates.CUSTOM_COMPONENTS_SOURCE.render(
|
templates.custom_components_source().render(
|
||||||
component_class_name=component_class_name, module_name=module_name
|
component_class_name=component_class_name, module_name=module_name
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
init_path = custom_component_src_dir / CustomComponents.INIT_FILE
|
init_path = custom_component_src_dir / CustomComponents.INIT_FILE
|
||||||
init_path.write_text(
|
init_path.write_text(
|
||||||
templates.CUSTOM_COMPONENTS_INIT_FILE.render(module_name=module_name)
|
templates.custom_components_init.render(module_name=module_name)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -164,7 +164,7 @@ def _populate_demo_app(name_variants: NameVariants):
|
|||||||
# This source file is rendered using jinja template file.
|
# This source file is rendered using jinja template file.
|
||||||
with open(f"{demo_app_name}/{demo_app_name}.py", "w") as f:
|
with open(f"{demo_app_name}/{demo_app_name}.py", "w") as f:
|
||||||
f.write(
|
f.write(
|
||||||
templates.CUSTOM_COMPONENTS_DEMO_APP.render(
|
templates.custom_components_demo_app().render(
|
||||||
custom_component_module_dir=name_variants.custom_component_module_dir,
|
custom_component_module_dir=name_variants.custom_component_module_dir,
|
||||||
module_name=name_variants.module_name,
|
module_name=name_variants.module_name,
|
||||||
)
|
)
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
# WARNING: do not import any modules that contain rx.State subclasses here
|
||||||
import atexit
|
import atexit
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
@ -16,8 +17,8 @@ from reflex_cli.v2.deployments import check_version, hosting_cli
|
|||||||
from reflex import constants
|
from reflex import constants
|
||||||
from reflex.config import environment, get_config
|
from reflex.config import environment, get_config
|
||||||
from reflex.custom_components.custom_components import custom_components_cli
|
from reflex.custom_components.custom_components import custom_components_cli
|
||||||
from reflex.state import reset_disk_state_manager
|
|
||||||
from reflex.utils import console, telemetry
|
from reflex.utils import console, telemetry
|
||||||
|
from reflex.utils.exec import set_env_mode
|
||||||
|
|
||||||
# Disable typer+rich integration for help panels
|
# Disable typer+rich integration for help panels
|
||||||
typer.core.rich = None # type: ignore
|
typer.core.rich = None # type: ignore
|
||||||
@ -134,14 +135,16 @@ def _run(
|
|||||||
loglevel: constants.LogLevel = config.loglevel,
|
loglevel: constants.LogLevel = config.loglevel,
|
||||||
):
|
):
|
||||||
"""Run the app in the given directory."""
|
"""Run the app in the given directory."""
|
||||||
|
# Set env mode in the environment
|
||||||
|
# This must be set before importing modules that contain rx.State subclasses
|
||||||
|
set_env_mode(env)
|
||||||
|
|
||||||
|
from reflex.state import reset_disk_state_manager
|
||||||
from reflex.utils import build, exec, prerequisites, processes
|
from reflex.utils import build, exec, prerequisites, processes
|
||||||
|
|
||||||
# Set the log level.
|
# Set the log level.
|
||||||
console.set_log_level(loglevel)
|
console.set_log_level(loglevel)
|
||||||
|
|
||||||
# Set env mode in the environment
|
|
||||||
environment.REFLEX_ENV_MODE.set(env)
|
|
||||||
|
|
||||||
# Show system info
|
# Show system info
|
||||||
exec.output_system_info()
|
exec.output_system_info()
|
||||||
|
|
||||||
@ -314,6 +317,10 @@ def export(
|
|||||||
),
|
),
|
||||||
):
|
):
|
||||||
"""Export the app to a zip file."""
|
"""Export the app to a zip file."""
|
||||||
|
# Set env mode in the environment
|
||||||
|
# This must be set before importing modules that contain rx.State subclasses
|
||||||
|
set_env_mode(constants.Env.PROD)
|
||||||
|
|
||||||
from reflex.utils import export as export_utils
|
from reflex.utils import export as export_utils
|
||||||
from reflex.utils import prerequisites
|
from reflex.utils import prerequisites
|
||||||
|
|
||||||
@ -660,6 +667,10 @@ def deployv2(
|
|||||||
),
|
),
|
||||||
):
|
):
|
||||||
"""Deploy the app to the Reflex hosting service."""
|
"""Deploy the app to the Reflex hosting service."""
|
||||||
|
# Set env mode in the environment
|
||||||
|
# This must be set before importing modules that contain rx.State subclasses
|
||||||
|
set_env_mode(constants.Env.PROD)
|
||||||
|
|
||||||
from reflex_cli.v2 import cli as hosting_cli
|
from reflex_cli.v2 import cli as hosting_cli
|
||||||
from reflex_cli.v2.utils import dependency
|
from reflex_cli.v2.utils import dependency
|
||||||
|
|
||||||
|
104
reflex/state.py
104
reflex/state.py
@ -301,6 +301,61 @@ def get_var_for_field(cls: Type[BaseState], f: ModelField):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Keep track of all state instances to calculate minified state names
|
||||||
|
state_count: int = 0
|
||||||
|
|
||||||
|
minified_state_names: Dict[str, str] = {}
|
||||||
|
|
||||||
|
|
||||||
|
def next_minified_state_name() -> str:
|
||||||
|
"""Get the next minified state name.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The next minified state name.
|
||||||
|
"""
|
||||||
|
global state_count
|
||||||
|
num = state_count
|
||||||
|
|
||||||
|
# All possible chars for minified state name
|
||||||
|
chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_"
|
||||||
|
base = len(chars)
|
||||||
|
state_name = ""
|
||||||
|
|
||||||
|
if num == 0:
|
||||||
|
state_name = chars[0]
|
||||||
|
|
||||||
|
while num > 0:
|
||||||
|
state_name = chars[num % base] + state_name
|
||||||
|
num = num // base
|
||||||
|
|
||||||
|
state_count += 1
|
||||||
|
|
||||||
|
return state_name
|
||||||
|
|
||||||
|
|
||||||
|
def get_minified_state_name(state_name: str) -> str:
|
||||||
|
"""Generate a minified state name.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
state_name: The state name to minify.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The minified state name.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: If no more minified state names are available
|
||||||
|
"""
|
||||||
|
if state_name in minified_state_names:
|
||||||
|
return minified_state_names[state_name]
|
||||||
|
|
||||||
|
while name := next_minified_state_name():
|
||||||
|
if name in minified_state_names.values():
|
||||||
|
continue
|
||||||
|
minified_state_names[state_name] = name
|
||||||
|
return name
|
||||||
|
raise ValueError("No more minified state names available")
|
||||||
|
|
||||||
|
|
||||||
class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
||||||
"""The state of the app."""
|
"""The state of the app."""
|
||||||
|
|
||||||
@ -499,18 +554,23 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|||||||
if parent_state is not None:
|
if parent_state is not None:
|
||||||
cls.inherited_vars = parent_state.vars
|
cls.inherited_vars = parent_state.vars
|
||||||
cls.inherited_backend_vars = parent_state.backend_vars
|
cls.inherited_backend_vars = parent_state.backend_vars
|
||||||
|
else:
|
||||||
|
# Track class_subclasses of the BaseState
|
||||||
|
parent_state = BaseState
|
||||||
|
|
||||||
# Check if another substate class with the same name has already been defined.
|
# Check if another substate class with the same name has already been defined.
|
||||||
if cls.get_name() in set(
|
#if not _reflex_internal_reinit and cls.get_name() in set(
|
||||||
c.get_name() for c in parent_state.class_subclasses
|
if cls.get_name() in set(
|
||||||
):
|
c.get_name() for c in parent_state.class_subclasses
|
||||||
# This should not happen, since we have added module prefix to state names in #3214
|
):
|
||||||
raise StateValueError(
|
breakpoint()
|
||||||
f"The substate class '{cls.get_name()}' has been defined multiple times. "
|
# This should not happen, since we have added module prefix to state names in #3214
|
||||||
"Shadowing substate classes is not allowed."
|
raise StateValueError(
|
||||||
)
|
f"The substate class '{cls.get_name()}' has been defined multiple times. "
|
||||||
# Track this new subclass in the parent state's subclasses set.
|
"Shadowing substate classes is not allowed."
|
||||||
parent_state.class_subclasses.add(cls)
|
)
|
||||||
|
# Track this new subclass in the parent state's subclasses set.
|
||||||
|
parent_state.class_subclasses.add(cls)
|
||||||
|
|
||||||
# Get computed vars.
|
# Get computed vars.
|
||||||
computed_vars = cls._get_computed_vars()
|
computed_vars = cls._get_computed_vars()
|
||||||
@ -896,7 +956,10 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|||||||
The name of the state.
|
The name of the state.
|
||||||
"""
|
"""
|
||||||
module = cls.__module__.replace(".", "___")
|
module = cls.__module__.replace(".", "___")
|
||||||
return format.to_snake_case(f"{module}___{cls.__name__}")
|
state_name = format.to_snake_case(f"{module}___{cls.__name__}")
|
||||||
|
if environment.REFLEX_MINIFY_STATES.get():
|
||||||
|
return get_minified_state_name(state_name)
|
||||||
|
return state_name
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@functools.lru_cache()
|
@functools.lru_cache()
|
||||||
@ -912,6 +975,21 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|||||||
name = ".".join((parent_state.get_full_name(), name))
|
name = ".".join((parent_state.get_full_name(), name))
|
||||||
return name
|
return name
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _reset_name_cache(cls):
|
||||||
|
"""Reset `get_name` and `get_full_name` cache to use minified state names."""
|
||||||
|
subclasses = sorted(cls.class_subclasses, key=lambda x: x.__name__)
|
||||||
|
cls.get_name.cache_clear()
|
||||||
|
cls.get_full_name.cache_clear()
|
||||||
|
if cls is BaseState:
|
||||||
|
cls.class_subclasses.clear()
|
||||||
|
else:
|
||||||
|
cls.__init_subclass__()
|
||||||
|
print(f"REINIT {cls.__name__} ({cls.get_full_name()})")
|
||||||
|
print(minified_state_names)
|
||||||
|
for subcls in subclasses:
|
||||||
|
subcls._reset_name_cache()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@functools.lru_cache()
|
@functools.lru_cache()
|
||||||
def get_class_substate(cls, path: Sequence[str] | str) -> Type[BaseState]:
|
def get_class_substate(cls, path: Sequence[str] | str) -> Type[BaseState]:
|
||||||
@ -1600,6 +1678,8 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
|
|||||||
raise ValueError(
|
raise ValueError(
|
||||||
"The value of state cannot be None when processing an event."
|
"The value of state cannot be None when processing an event."
|
||||||
)
|
)
|
||||||
|
if name not in substate.event_handlers:
|
||||||
|
breakpoint()
|
||||||
handler = substate.event_handlers[name]
|
handler = substate.event_handlers[name]
|
||||||
|
|
||||||
# For background tasks, proxy the state
|
# For background tasks, proxy the state
|
||||||
|
@ -46,12 +46,15 @@ import reflex.utils.processes
|
|||||||
from reflex.config import environment
|
from reflex.config import environment
|
||||||
from reflex.state import (
|
from reflex.state import (
|
||||||
BaseState,
|
BaseState,
|
||||||
|
State,
|
||||||
StateManager,
|
StateManager,
|
||||||
StateManagerDisk,
|
StateManagerDisk,
|
||||||
StateManagerMemory,
|
StateManagerMemory,
|
||||||
StateManagerRedis,
|
StateManagerRedis,
|
||||||
|
minified_state_names,
|
||||||
reload_state_module,
|
reload_state_module,
|
||||||
)
|
)
|
||||||
|
from reflex.utils.types import override
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from selenium import webdriver # pyright: ignore [reportMissingImports]
|
from selenium import webdriver # pyright: ignore [reportMissingImports]
|
||||||
@ -141,7 +144,7 @@ class AppHarness:
|
|||||||
Callable[[], None] | types.ModuleType | str | functools.partial[Any]
|
Callable[[], None] | types.ModuleType | str | functools.partial[Any]
|
||||||
] = None,
|
] = None,
|
||||||
app_name: Optional[str] = None,
|
app_name: Optional[str] = None,
|
||||||
) -> "AppHarness":
|
) -> AppHarness:
|
||||||
"""Create an AppHarness instance at root.
|
"""Create an AppHarness instance at root.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -192,9 +195,12 @@ class AppHarness:
|
|||||||
Returns:
|
Returns:
|
||||||
The state name
|
The state name
|
||||||
"""
|
"""
|
||||||
return reflex.utils.format.to_snake_case(
|
state_name = reflex.utils.format.to_snake_case(
|
||||||
f"{self.app_name}___{self.app_name}___" + state_cls_name
|
f"{self.app_name}___{self.app_name}___" + state_cls_name
|
||||||
)
|
)
|
||||||
|
if environment.REFLEX_MINIFY_STATES.get():
|
||||||
|
return minified_state_names.get(state_name, state_name)
|
||||||
|
return state_name
|
||||||
|
|
||||||
def get_full_state_name(self, path: List[str]) -> str:
|
def get_full_state_name(self, path: List[str]) -> str:
|
||||||
"""Get the full state name for the given state class name.
|
"""Get the full state name for the given state class name.
|
||||||
@ -207,7 +213,7 @@ class AppHarness:
|
|||||||
"""
|
"""
|
||||||
# NOTE: using State.get_name() somehow causes trouble here
|
# NOTE: using State.get_name() somehow causes trouble here
|
||||||
# path = [State.get_name()] + [self.get_state_name(p) for p in path]
|
# path = [State.get_name()] + [self.get_state_name(p) for p in path]
|
||||||
path = ["reflex___state____state"] + [self.get_state_name(p) for p in path]
|
path = [State.get_name()] + [self.get_state_name(p) for p in path]
|
||||||
return ".".join(path)
|
return ".".join(path)
|
||||||
|
|
||||||
def _get_globals_from_signature(self, func: Any) -> dict[str, Any]:
|
def _get_globals_from_signature(self, func: Any) -> dict[str, Any]:
|
||||||
@ -412,7 +418,7 @@ class AppHarness:
|
|||||||
self.frontend_output_thread = threading.Thread(target=consume_frontend_output)
|
self.frontend_output_thread = threading.Thread(target=consume_frontend_output)
|
||||||
self.frontend_output_thread.start()
|
self.frontend_output_thread.start()
|
||||||
|
|
||||||
def start(self) -> "AppHarness":
|
def start(self) -> AppHarness:
|
||||||
"""Start the backend in a new thread and dev frontend as a separate process.
|
"""Start the backend in a new thread and dev frontend as a separate process.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
@ -442,7 +448,7 @@ class AppHarness:
|
|||||||
return f"{key} = {value!r}"
|
return f"{key} = {value!r}"
|
||||||
return inspect.getsource(value)
|
return inspect.getsource(value)
|
||||||
|
|
||||||
def __enter__(self) -> "AppHarness":
|
def __enter__(self) -> AppHarness:
|
||||||
"""Contextmanager protocol for `start()`.
|
"""Contextmanager protocol for `start()`.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
@ -921,6 +927,7 @@ class AppHarnessProd(AppHarness):
|
|||||||
)
|
)
|
||||||
self.frontend_server.serve_forever()
|
self.frontend_server.serve_forever()
|
||||||
|
|
||||||
|
@override
|
||||||
def _start_frontend(self):
|
def _start_frontend(self):
|
||||||
# Set up the frontend.
|
# Set up the frontend.
|
||||||
with chdir(self.app_path):
|
with chdir(self.app_path):
|
||||||
@ -932,17 +939,19 @@ class AppHarnessProd(AppHarness):
|
|||||||
zipping=False,
|
zipping=False,
|
||||||
frontend=True,
|
frontend=True,
|
||||||
backend=False,
|
backend=False,
|
||||||
loglevel=reflex.constants.LogLevel.INFO,
|
loglevel=reflex.constants.base.LogLevel.INFO,
|
||||||
)
|
)
|
||||||
|
|
||||||
self.frontend_thread = threading.Thread(target=self._run_frontend)
|
self.frontend_thread = threading.Thread(target=self._run_frontend)
|
||||||
self.frontend_thread.start()
|
self.frontend_thread.start()
|
||||||
|
|
||||||
|
@override
|
||||||
def _wait_frontend(self):
|
def _wait_frontend(self):
|
||||||
self._poll_for(lambda: self.frontend_server is not None)
|
_ = self._poll_for(lambda: self.frontend_server is not None)
|
||||||
if self.frontend_server is None or not self.frontend_server.socket.fileno():
|
if self.frontend_server is None or not self.frontend_server.socket.fileno():
|
||||||
raise RuntimeError("Frontend did not start")
|
raise RuntimeError("Frontend did not start")
|
||||||
|
|
||||||
|
@override
|
||||||
def _start_backend(self):
|
def _start_backend(self):
|
||||||
if self.app_instance is None:
|
if self.app_instance is None:
|
||||||
raise RuntimeError("App was not initialized.")
|
raise RuntimeError("App was not initialized.")
|
||||||
@ -959,12 +968,14 @@ class AppHarnessProd(AppHarness):
|
|||||||
self.backend_thread = threading.Thread(target=self.backend.run)
|
self.backend_thread = threading.Thread(target=self.backend.run)
|
||||||
self.backend_thread.start()
|
self.backend_thread.start()
|
||||||
|
|
||||||
|
@override
|
||||||
def _poll_for_servers(self, timeout: TimeoutType = None) -> socket.socket:
|
def _poll_for_servers(self, timeout: TimeoutType = None) -> socket.socket:
|
||||||
try:
|
try:
|
||||||
return super()._poll_for_servers(timeout)
|
return super()._poll_for_servers(timeout)
|
||||||
finally:
|
finally:
|
||||||
environment.REFLEX_SKIP_COMPILE.set(None)
|
environment.REFLEX_SKIP_COMPILE.set(None)
|
||||||
|
|
||||||
|
@override
|
||||||
def stop(self):
|
def stop(self):
|
||||||
"""Stop the frontend python webserver."""
|
"""Stop the frontend python webserver."""
|
||||||
super().stop()
|
super().stop()
|
||||||
|
@ -44,7 +44,7 @@ def generate_sitemap_config(deploy_url: str, export=False):
|
|||||||
config = json.dumps(config)
|
config = json.dumps(config)
|
||||||
|
|
||||||
sitemap = prerequisites.get_web_dir() / constants.Next.SITEMAP_CONFIG_FILE
|
sitemap = prerequisites.get_web_dir() / constants.Next.SITEMAP_CONFIG_FILE
|
||||||
sitemap.write_text(templates.SITEMAP_CONFIG(config=config))
|
sitemap.write_text(templates.sitemap_config()(config=config))
|
||||||
|
|
||||||
|
|
||||||
def _zip(
|
def _zip(
|
||||||
|
@ -497,6 +497,19 @@ def is_prod_mode() -> bool:
|
|||||||
return current_mode == constants.Env.PROD
|
return current_mode == constants.Env.PROD
|
||||||
|
|
||||||
|
|
||||||
|
def set_env_mode(mode: constants.Env):
|
||||||
|
"""Mark the app as running in dev or prod mode.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
mode: The mode to set the app to.
|
||||||
|
"""
|
||||||
|
environment.REFLEX_ENV_MODE.set(mode)
|
||||||
|
from reflex.state import BaseState
|
||||||
|
|
||||||
|
# Ensure that minified names are or are not used based on the mode.
|
||||||
|
BaseState._reset_name_cache()
|
||||||
|
|
||||||
|
|
||||||
def is_frontend_only() -> bool:
|
def is_frontend_only() -> bool:
|
||||||
"""Check if the app is running in frontend-only mode.
|
"""Check if the app is running in frontend-only mode.
|
||||||
|
|
||||||
|
@ -441,7 +441,7 @@ def create_config(app_name: str):
|
|||||||
config_name = f"{re.sub(r'[^a-zA-Z]', '', app_name).capitalize()}Config"
|
config_name = f"{re.sub(r'[^a-zA-Z]', '', app_name).capitalize()}Config"
|
||||||
with open(constants.Config.FILE, "w") as f:
|
with open(constants.Config.FILE, "w") as f:
|
||||||
console.debug(f"Creating {constants.Config.FILE}")
|
console.debug(f"Creating {constants.Config.FILE}")
|
||||||
f.write(templates.RXCONFIG.render(app_name=app_name, config_name=config_name))
|
f.write(templates.rxconfig().render(app_name=app_name, config_name=config_name))
|
||||||
|
|
||||||
|
|
||||||
def initialize_gitignore(
|
def initialize_gitignore(
|
||||||
@ -611,7 +611,7 @@ def initialize_web_directory():
|
|||||||
|
|
||||||
|
|
||||||
def _compile_package_json():
|
def _compile_package_json():
|
||||||
return templates.PACKAGE_JSON.render(
|
return templates.package_json().render(
|
||||||
scripts={
|
scripts={
|
||||||
"dev": constants.PackageJson.Commands.DEV,
|
"dev": constants.PackageJson.Commands.DEV,
|
||||||
"export": constants.PackageJson.Commands.EXPORT,
|
"export": constants.PackageJson.Commands.EXPORT,
|
||||||
|
@ -3,10 +3,13 @@
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import Generator, Type
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
import reflex.constants
|
||||||
from reflex.config import environment
|
from reflex.config import environment
|
||||||
|
from reflex.constants.base import Env
|
||||||
from reflex.testing import AppHarness, AppHarnessProd
|
from reflex.testing import AppHarness, AppHarnessProd
|
||||||
|
|
||||||
DISPLAY = None
|
DISPLAY = None
|
||||||
@ -64,15 +67,30 @@ def pytest_exception_interact(node, call, report):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture(
|
@pytest.fixture(
|
||||||
scope="session", params=[AppHarness, AppHarnessProd], ids=["dev", "prod"]
|
scope="session",
|
||||||
|
params=[
|
||||||
|
AppHarness,
|
||||||
|
AppHarnessProd,
|
||||||
|
],
|
||||||
|
ids=[
|
||||||
|
reflex.constants.Env.DEV.value,
|
||||||
|
reflex.constants.Env.PROD.value,
|
||||||
|
],
|
||||||
)
|
)
|
||||||
def app_harness_env(request):
|
def app_harness_env(
|
||||||
|
request: pytest.FixtureRequest,
|
||||||
|
) -> Generator[Type[AppHarness], None, None]:
|
||||||
"""Parametrize the AppHarness class to use for the test, either dev or prod.
|
"""Parametrize the AppHarness class to use for the test, either dev or prod.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
request: The pytest fixture request object.
|
request: The pytest fixture request object.
|
||||||
|
|
||||||
Returns:
|
Yields:
|
||||||
The AppHarness class to use for the test.
|
The AppHarness class to use for the test.
|
||||||
"""
|
"""
|
||||||
return request.param
|
harness: Type[AppHarness] = request.param
|
||||||
|
if issubclass(harness, AppHarnessProd):
|
||||||
|
environment.REFLEX_ENV_MODE.set(Env.PROD)
|
||||||
|
yield harness
|
||||||
|
if isinstance(harness, AppHarnessProd):
|
||||||
|
environment.REFLEX_ENV_MODE.set(None)
|
||||||
|
@ -106,7 +106,6 @@ def ComputedVars():
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
# raise Exception(State.count3._deps(objclass=State))
|
|
||||||
app = rx.App()
|
app = rx.App()
|
||||||
app.add_page(index)
|
app.add_page(index)
|
||||||
|
|
||||||
|
161
tests/integration/test_minified_states.py
Normal file
161
tests/integration/test_minified_states.py
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
"""Integration tests for minified state names."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from functools import partial
|
||||||
|
from typing import Generator, Optional, Type
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from selenium.webdriver.common.by import By
|
||||||
|
from selenium.webdriver.remote.webdriver import WebDriver
|
||||||
|
|
||||||
|
from reflex.config import environment
|
||||||
|
from reflex.testing import AppHarness, AppHarnessProd
|
||||||
|
|
||||||
|
|
||||||
|
def MinifiedStatesApp(minify: bool | None) -> None:
|
||||||
|
"""A test app for minified state names.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
minify: whether to minify state names
|
||||||
|
"""
|
||||||
|
import reflex as rx
|
||||||
|
|
||||||
|
class MinifiedState(rx.State):
|
||||||
|
"""State for the MinifiedStatesApp app."""
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
app = rx.App()
|
||||||
|
|
||||||
|
def index():
|
||||||
|
return rx.vstack(
|
||||||
|
rx.input(
|
||||||
|
value=MinifiedState.router.session.client_token,
|
||||||
|
is_read_only=True,
|
||||||
|
id="token",
|
||||||
|
),
|
||||||
|
rx.text(f"minify: {minify}", id="minify"),
|
||||||
|
rx.text(MinifiedState.get_name(), id="state_name"),
|
||||||
|
rx.text(MinifiedState.get_full_name(), id="state_full_name"),
|
||||||
|
)
|
||||||
|
|
||||||
|
app.add_page(index)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(
|
||||||
|
params=[
|
||||||
|
pytest.param(False),
|
||||||
|
pytest.param(True),
|
||||||
|
pytest.param(None),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def minify_state_env(
|
||||||
|
request: pytest.FixtureRequest,
|
||||||
|
) -> Generator[Optional[bool], None, None]:
|
||||||
|
"""Set the environment variable to minify state names.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
request: pytest fixture request
|
||||||
|
|
||||||
|
Yields:
|
||||||
|
minify_states: whether to minify state names
|
||||||
|
"""
|
||||||
|
minify_states: Optional[bool] = request.param
|
||||||
|
environment.REFLEX_MINIFY_STATES.set(minify_states)
|
||||||
|
yield minify_states
|
||||||
|
environment.REFLEX_MINIFY_STATES.set(None)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def test_app(
|
||||||
|
app_harness_env: Type[AppHarness],
|
||||||
|
tmp_path_factory: pytest.TempPathFactory,
|
||||||
|
minify_state_env: Optional[bool],
|
||||||
|
) -> Generator[AppHarness, None, None]:
|
||||||
|
"""Start MinifiedStatesApp app at tmp_path via AppHarness.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
app_harness_env: either AppHarness (dev) or AppHarnessProd (prod)
|
||||||
|
tmp_path_factory: pytest tmp_path_factory fixture
|
||||||
|
minify_state_env: need to request this fixture to set env before the app starts
|
||||||
|
|
||||||
|
Yields:
|
||||||
|
running AppHarness instance
|
||||||
|
|
||||||
|
"""
|
||||||
|
name = f"testminifiedstates_{app_harness_env.__name__.lower()}"
|
||||||
|
with app_harness_env.create(
|
||||||
|
root=tmp_path_factory.mktemp(name),
|
||||||
|
app_name=name,
|
||||||
|
app_source=partial(MinifiedStatesApp, minify=minify_state_env), # type: ignore
|
||||||
|
) as harness:
|
||||||
|
yield harness
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def driver(test_app: AppHarness) -> Generator[WebDriver, None, None]:
|
||||||
|
"""Get an instance of the browser open to the test_app app.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
test_app: harness for MinifiedStatesApp app
|
||||||
|
|
||||||
|
Yields:
|
||||||
|
WebDriver instance.
|
||||||
|
|
||||||
|
"""
|
||||||
|
assert test_app.app_instance is not None, "app is not running"
|
||||||
|
driver = test_app.frontend()
|
||||||
|
try:
|
||||||
|
yield driver
|
||||||
|
finally:
|
||||||
|
driver.quit()
|
||||||
|
|
||||||
|
|
||||||
|
def test_minified_states(
|
||||||
|
test_app: AppHarness,
|
||||||
|
driver: WebDriver,
|
||||||
|
minify_state_env: Optional[bool],
|
||||||
|
) -> None:
|
||||||
|
"""Test minified state names.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
test_app: harness for MinifiedStatesApp
|
||||||
|
driver: WebDriver instance.
|
||||||
|
minify_state_env: whether state minification is enabled by env var.
|
||||||
|
|
||||||
|
"""
|
||||||
|
assert test_app.app_instance is not None, "app is not running"
|
||||||
|
|
||||||
|
is_prod = isinstance(test_app, AppHarnessProd)
|
||||||
|
|
||||||
|
# default to minifying in production
|
||||||
|
should_minify: bool = is_prod
|
||||||
|
|
||||||
|
# env overrides default
|
||||||
|
if minify_state_env is not None:
|
||||||
|
should_minify = minify_state_env
|
||||||
|
|
||||||
|
# get a reference to the connected client
|
||||||
|
token_input = driver.find_element(By.ID, "token")
|
||||||
|
assert token_input
|
||||||
|
|
||||||
|
# wait for the backend connection to send the token
|
||||||
|
token = test_app.poll_for_value(token_input)
|
||||||
|
assert token
|
||||||
|
|
||||||
|
state_name_text = driver.find_element(By.ID, "state_name")
|
||||||
|
assert state_name_text
|
||||||
|
state_name = state_name_text.text
|
||||||
|
|
||||||
|
state_full_name_text = driver.find_element(By.ID, "state_full_name")
|
||||||
|
assert state_full_name_text
|
||||||
|
_ = state_full_name_text.text
|
||||||
|
|
||||||
|
assert test_app.app_module
|
||||||
|
module_state_prefix = test_app.app_module.__name__.replace(".", "___")
|
||||||
|
|
||||||
|
if should_minify:
|
||||||
|
assert len(state_name) == 1
|
||||||
|
else:
|
||||||
|
assert state_name == f"{module_state_prefix}____minified_state"
|
14
tests/test_minify_state.py
Normal file
14
tests/test_minify_state.py
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
from typing import Set
|
||||||
|
|
||||||
|
from reflex.state import next_minified_state_name
|
||||||
|
|
||||||
|
|
||||||
|
def test_next_minified_state_name():
|
||||||
|
"""Test that the next_minified_state_name function returns unique state names."""
|
||||||
|
state_names: Set[str] = set()
|
||||||
|
gen = 10000
|
||||||
|
for _ in range(gen):
|
||||||
|
state_name = next_minified_state_name()
|
||||||
|
assert state_name not in state_names
|
||||||
|
state_names.add(state_name)
|
||||||
|
assert len(state_names) == gen
|
@ -1032,7 +1032,7 @@ async def test_dynamic_route_var_route_change_completed_on_load(
|
|||||||
prev_exp_val = ""
|
prev_exp_val = ""
|
||||||
for exp_index, exp_val in enumerate(exp_vals):
|
for exp_index, exp_val in enumerate(exp_vals):
|
||||||
on_load_internal = _event(
|
on_load_internal = _event(
|
||||||
name=f"{state.get_full_name()}.{constants.CompileVars.ON_LOAD_INTERNAL.rpartition('.')[2]}",
|
name=f"{state.get_full_name()}.on_load_internal",
|
||||||
val=exp_val,
|
val=exp_val,
|
||||||
)
|
)
|
||||||
exp_router_data = {
|
exp_router_data = {
|
||||||
|
@ -253,6 +253,11 @@ def test_env_var():
|
|||||||
INTERNAL: EnvVar[str] = env_var("default", internal=True)
|
INTERNAL: EnvVar[str] = env_var("default", internal=True)
|
||||||
BOOLEAN: EnvVar[bool] = env_var(False)
|
BOOLEAN: EnvVar[bool] = env_var(False)
|
||||||
|
|
||||||
|
# default_factory with other env_var as fallback
|
||||||
|
BLUBB_OR_BLA: EnvVar[str] = env_var(
|
||||||
|
default_factory=lambda: TestEnv.BLUBB.getenv() or "bla"
|
||||||
|
)
|
||||||
|
|
||||||
assert TestEnv.BLUBB.get() == "default"
|
assert TestEnv.BLUBB.get() == "default"
|
||||||
assert TestEnv.BLUBB.name == "BLUBB"
|
assert TestEnv.BLUBB.name == "BLUBB"
|
||||||
TestEnv.BLUBB.set("new")
|
TestEnv.BLUBB.set("new")
|
||||||
@ -280,3 +285,15 @@ def test_env_var():
|
|||||||
assert TestEnv.BOOLEAN.get() is False
|
assert TestEnv.BOOLEAN.get() is False
|
||||||
TestEnv.BOOLEAN.set(None)
|
TestEnv.BOOLEAN.set(None)
|
||||||
assert "BOOLEAN" not in os.environ
|
assert "BOOLEAN" not in os.environ
|
||||||
|
|
||||||
|
assert TestEnv.BLUBB_OR_BLA.get() == "bla"
|
||||||
|
TestEnv.BLUBB.set("new")
|
||||||
|
assert TestEnv.BLUBB_OR_BLA.get() == "new"
|
||||||
|
TestEnv.BLUBB.set(None)
|
||||||
|
assert TestEnv.BLUBB_OR_BLA.get() == "bla"
|
||||||
|
TestEnv.BLUBB_OR_BLA.set("test")
|
||||||
|
assert TestEnv.BLUBB_OR_BLA.get() == "test"
|
||||||
|
TestEnv.BLUBB.set("other")
|
||||||
|
assert TestEnv.BLUBB_OR_BLA.get() == "test"
|
||||||
|
TestEnv.BLUBB_OR_BLA.set(None)
|
||||||
|
TestEnv.BLUBB.set(None)
|
||||||
|
@ -66,6 +66,7 @@ CI = bool(os.environ.get("CI", False))
|
|||||||
LOCK_EXPIRATION = 2000 if CI else 300
|
LOCK_EXPIRATION = 2000 if CI else 300
|
||||||
LOCK_EXPIRE_SLEEP = 2.5 if CI else 0.4
|
LOCK_EXPIRE_SLEEP = 2.5 if CI else 0.4
|
||||||
|
|
||||||
|
ON_LOAD_INTERNAL = f"{OnLoadInternalState.get_name()}.on_load_internal"
|
||||||
|
|
||||||
formatted_router = {
|
formatted_router = {
|
||||||
"session": {"client_token": "", "client_ip": "", "session_id": ""},
|
"session": {"client_token": "", "client_ip": "", "session_id": ""},
|
||||||
@ -2818,7 +2819,7 @@ async def test_preprocess(app_module_mock, token, test_state, expected, mocker):
|
|||||||
app=app,
|
app=app,
|
||||||
event=Event(
|
event=Event(
|
||||||
token=token,
|
token=token,
|
||||||
name=f"{state.get_name()}.{CompileVars.ON_LOAD_INTERNAL}",
|
name=f"{state.get_name()}.{ON_LOAD_INTERNAL}",
|
||||||
router_data={RouteVar.PATH: "/", RouteVar.ORIGIN: "/", RouteVar.QUERY: {}},
|
router_data={RouteVar.PATH: "/", RouteVar.ORIGIN: "/", RouteVar.QUERY: {}},
|
||||||
),
|
),
|
||||||
sid="sid",
|
sid="sid",
|
||||||
@ -2865,7 +2866,7 @@ async def test_preprocess_multiple_load_events(app_module_mock, token, mocker):
|
|||||||
app=app,
|
app=app,
|
||||||
event=Event(
|
event=Event(
|
||||||
token=token,
|
token=token,
|
||||||
name=f"{state.get_full_name()}.{CompileVars.ON_LOAD_INTERNAL}",
|
name=f"{state.get_full_name()}.{ON_LOAD_INTERNAL}",
|
||||||
router_data={RouteVar.PATH: "/", RouteVar.ORIGIN: "/", RouteVar.QUERY: {}},
|
router_data={RouteVar.PATH: "/", RouteVar.ORIGIN: "/", RouteVar.QUERY: {}},
|
||||||
),
|
),
|
||||||
sid="sid",
|
sid="sid",
|
||||||
|
@ -271,7 +271,7 @@ def test_unsupported_literals(cls: type):
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_create_config(app_name, expected_config_name, mocker):
|
def test_create_config(app_name, expected_config_name, mocker):
|
||||||
"""Test templates.RXCONFIG is formatted with correct app name and config class name.
|
"""Test templates.rxconfig is formatted with correct app name and config class name.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
app_name: App name.
|
app_name: App name.
|
||||||
@ -279,9 +279,9 @@ def test_create_config(app_name, expected_config_name, mocker):
|
|||||||
mocker: Mocker object.
|
mocker: Mocker object.
|
||||||
"""
|
"""
|
||||||
mocker.patch("builtins.open")
|
mocker.patch("builtins.open")
|
||||||
tmpl_mock = mocker.patch("reflex.compiler.templates.RXCONFIG")
|
tmpl_mock = mocker.patch("reflex.compiler.templates.rxconfig")
|
||||||
prerequisites.create_config(app_name)
|
prerequisites.create_config(app_name)
|
||||||
tmpl_mock.render.assert_called_with(
|
tmpl_mock().render.assert_called_with(
|
||||||
app_name=app_name, config_name=expected_config_name
|
app_name=app_name, config_name=expected_config_name
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -592,8 +592,23 @@ def test_style_prop_with_event_handler_value(callable):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_is_prod_mode() -> None:
|
@pytest.fixture
|
||||||
"""Test that the prod mode is correctly determined."""
|
def cleanup_reflex_env_mode():
|
||||||
|
"""Cleanup the reflex env mode.
|
||||||
|
|
||||||
|
Yields:
|
||||||
|
None
|
||||||
|
"""
|
||||||
|
yield
|
||||||
|
environment.REFLEX_ENV_MODE.set(None)
|
||||||
|
|
||||||
|
|
||||||
|
def test_is_prod_mode(cleanup_reflex_env_mode: None) -> None:
|
||||||
|
"""Test that the prod mode is correctly determined.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
cleanup_reflex_env_mode: Fixture to cleanup the reflex env mode.
|
||||||
|
"""
|
||||||
environment.REFLEX_ENV_MODE.set(constants.Env.PROD)
|
environment.REFLEX_ENV_MODE.set(constants.Env.PROD)
|
||||||
assert utils_exec.is_prod_mode()
|
assert utils_exec.is_prod_mode()
|
||||||
environment.REFLEX_ENV_MODE.set(None)
|
environment.REFLEX_ENV_MODE.set(None)
|
||||||
|
Loading…
Reference in New Issue
Block a user