apps should no longer call "app.compile()" (#2291)

This commit is contained in:
jackie-pc 2023-12-18 16:06:21 -08:00 committed by GitHub
parent 3c07537c11
commit 7388617b72
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 62 additions and 52 deletions

View File

@ -123,7 +123,6 @@ def index():
# Add state and page to the app.
app = rx.App()
app.add_page(index, title="reflex:DALL·E")
app.compile()
```
## Let's break this down.

View File

@ -121,7 +121,6 @@ def index():
# Add state and page to the app.
app = rx.App()
app.add_page(index, title="reflex:DALL·E")
app.compile()
```
## Vamos a desglosarlo.
@ -191,7 +190,6 @@ Añadimos una página desde la raíz (root) de la aplicación al componente de
```python
app.add_page(index, title="DALL-E")
app.compile()
```
Puedes crear una aplicación multipágina añadiendo más páginas.

View File

@ -120,7 +120,6 @@ def index():
# Add state and page to the app.
app = rx.App()
app.add_page(index, title="reflex:DALL·E")
app.compile()
```
## चलो इसे विस्तार से देखते हैं।
@ -190,7 +189,6 @@ app = rx.App()
```python
app.add_page(index, title="DALL-E")
app.compile()
```
आप और पेज जोड़कर एक मल्टी-पेज एप्लिकेशन बना सकते हैं।

View File

@ -121,7 +121,6 @@ def index():
# Aggiungi stato e pagina all'app.
app = rx.App()
app.add_page(index, title="reflex:DALL·E")
app.compile()
```
## Analizziamolo
@ -191,7 +190,6 @@ Possiamo aggiungere una pagina dalla radice dell'app al componente dell'indice.A
```python
app.add_page(index, title="DALL-E")
app.compile()
```
Puoi creare un'app multi-pagina aggiungendo altre pagine.

View File

@ -121,7 +121,6 @@ def index():
# Add state and page to the app.
app = rx.App()
app.add_page(index, title="reflex:DALL·E")
app.compile()
```
## 하나씩 살펴보겠습니다.
@ -194,7 +193,6 @@ app = rx.App()
```python
app.add_page(index, title="DALL-E")
app.compile()
```
여러 페이지를 추가하여 멀티 페이지 앱을 만들 수 있습니다.

View File

@ -121,7 +121,6 @@ def index():
# Adição do estado e da página no app.
app = rx.App()
app.add_page(index, title="reflex:DALL·E")
app.compile()
```
## Vamos por partes.
@ -192,7 +191,6 @@ Adicionamos uma página na raíz do app, apontando para o componente index. Tamb
```python
app.add_page(index, title="DALL-E")
app.compile()
```
Você pode criar mais páginas e adicioná-las ao seu app.

View File

@ -124,7 +124,6 @@ def index():
# Sayfa ve durumu uygulamaya ekleyin.
app = rx.App()
app.add_page(index, title="reflex:DALL·E")
app.compile()
```
## Daha Detaylı İceleyelim
@ -194,7 +193,6 @@ Uygulamamızın kök dizinine index bileşeninden bir sayfa ekliyoruz. Ayrıca s
```python
app.add_page(index, title="DALL-E")
app.compile()
```
Daha fazla sayfa ekleyerek çok sayfalı bir uygulama oluşturabilirsiniz.

View File

@ -122,7 +122,6 @@ def index():
# Add state and page to the app.
app = rx.App()
app.add_page(index, title="reflex:DALL·E")
app.compile()
```
## 让我们分解以上步骤.
@ -194,7 +193,6 @@ app = rx.App()
```python
app.add_page(index, title="DALL-E")
app.compile()
```
您可以通过增加更多页面来创建一个多页面的应用.

View File

@ -121,7 +121,6 @@ def index():
# 把狀態跟頁面添加到應用程式。
app = rx.App()
app.add_page(index, title="reflex:DALL·E")
app.compile()
```
## 讓我們來拆解一下。
@ -192,7 +191,6 @@ app = rx.App()
```python
app.add_page(index, title="DALL-E")
app.compile()
```
你可以添加更多頁面至路由藉此來建立多頁面應用程式(multi-page app)

View File

@ -95,7 +95,6 @@ def BackgroundTask():
app = rx.App(state=rx.State)
app.add_page(index)
app.compile()
@pytest.fixture(scope="session")

View File

@ -227,8 +227,6 @@ def CallScript():
rx.button("Reset", id="reset", on_click=CallScriptState.reset_),
)
app.compile()
@pytest.fixture(scope="session")
def call_script(tmp_path_factory) -> Generator[AppHarness, None, None]:

View File

@ -100,7 +100,6 @@ def ClientSide():
app = rx.App(state=rx.State)
app.add_page(index)
app.add_page(index, route="/foo")
app.compile()
@pytest.fixture(scope="session")

View File

@ -21,7 +21,6 @@ def ConnectionBanner():
app = rx.App(state=rx.State)
app.add_page(index)
app.compile()
@pytest.fixture()

View File

@ -66,7 +66,6 @@ def DynamicRoute():
app.add_page(index, route="/page/[page_id]", on_load=DynamicState.on_load) # type: ignore
app.add_page(index, route="/static/x", on_load=DynamicState.on_load) # type: ignore
app.add_custom_404_page(on_load=DynamicState.on_load) # type: ignore
app.compile()
@pytest.fixture(scope="session")

View File

@ -132,7 +132,6 @@ def TestEventAction():
app = rx.App(state=rx.State)
app.add_page(index)
app.compile()
@pytest.fixture(scope="session")

View File

@ -242,8 +242,6 @@ def EventChain():
app.add_page(on_mount_return_chain)
app.add_page(on_mount_yield_chain)
app.compile()
@pytest.fixture(scope="session")
def event_chain(tmp_path_factory) -> Generator[AppHarness, None, None]:

View File

@ -62,8 +62,6 @@ def FormSubmit():
height="100vh",
)
app.compile()
def FormSubmitName():
"""App with a form using on_submit."""
@ -124,8 +122,6 @@ def FormSubmitName():
height="100vh",
)
app.compile()
@pytest.fixture(
scope="session", params=[FormSubmit, FormSubmitName], ids=["id", "name"]

View File

@ -40,8 +40,6 @@ def FullyControlledInput():
rx.button("CLEAR", on_click=rx.set_value("on_change_input", "")),
)
app.compile()
@pytest.fixture()
def fully_controlled_input(tmp_path) -> Generator[AppHarness, None, None]:

View File

@ -45,7 +45,6 @@ def LoginSample():
app = rx.App(state=rx.State)
app.add_page(index)
app.add_page(login)
app.compile()
@pytest.fixture(scope="session")

View File

@ -75,8 +75,6 @@ def ServerSideEvent():
),
)
app.compile()
@pytest.fixture(scope="session")
def server_side_event(tmp_path_factory) -> Generator[AppHarness, None, None]:

View File

@ -88,8 +88,6 @@ def Table():
)
)
app.compile()
@pytest.fixture()
def table(tmp_path_factory) -> Generator[AppHarness, None, None]:

View File

@ -115,7 +115,6 @@ def UploadFile():
app = rx.App(state=rx.State)
app.add_page(index)
app.compile()
@pytest.fixture(scope="session")

View File

@ -565,8 +565,6 @@ def VarOperations():
),
)
app.compile()
@pytest.fixture(scope="session")
def var_operations(tmp_path_factory) -> Generator[AppHarness, None, None]:

View File

@ -619,6 +619,19 @@ class App(Base):
return True
def compile(self):
"""compile_() is the new function for performing compilation.
Reflex framework will call it automatically as needed.
"""
console.deprecate(
feature_name="app.compile()",
reason="Explicit calls to app.compile() are not needed."
" Method will be removed in 0.4.0",
deprecation_version="0.3.8",
removal_version="0.4.0",
)
return
def compile_(self):
"""Compile the app and output it to the pages folder."""
# add the pages before the compile check so App know onload methods
for render, kwargs in DECORATED_PAGES:

View File

@ -120,6 +120,7 @@ class App(Base):
def setup_admin_dash(self) -> None: ...
def get_frontend_packages(self, imports: Dict[str, str]): ...
def compile(self) -> None: ...
def compile_(self) -> None: ...
def modify_state(self, token: str) -> AsyncContextManager[State]: ...
def _process_background(
self, state: State, event: Event

View File

@ -0,0 +1,13 @@
"""Shims the real reflex app module for running backend server (uvicorn or gunicorn).
Only the app attribute is explicitly exposed.
"""
from reflex import constants
from reflex.utils.prerequisites import get_compiled_app
if "app" != constants.CompileVars.APP:
raise AssertionError("unexpected variable name for 'app'")
app = getattr(get_compiled_app(), constants.CompileVars.APP)
# ensure only "app" is exposed.
del get_compiled_app
del constants

View File

@ -178,7 +178,7 @@ def _run(
if frontend:
prerequisites.update_next_config()
# Get the app module.
prerequisites.get_app()
prerequisites.get_compiled_app()
# Warn if schema is not up to date.
prerequisites.check_schema_up_to_date()
@ -362,7 +362,7 @@ def db_init():
# Initialize the database.
_skip_compile()
prerequisites.get_app()
prerequisites.get_compiled_app()
model.Model.alembic_init()
model.Model.migrate(autogenerate=True)
@ -373,8 +373,9 @@ def migrate():
from reflex import model
from reflex.utils import prerequisites
# TODO see if we can use `get_app()` instead (no compile). Would _skip_compile still be needed then?
_skip_compile()
prerequisites.get_app()
prerequisites.get_compiled_app()
if not prerequisites.check_db_initialized():
return
model.Model.migrate()
@ -393,8 +394,9 @@ def makemigrations(
from reflex import model
from reflex.utils import prerequisites
# TODO see if we can use `get_app()` instead (no compile). Would _skip_compile still be needed then?
_skip_compile()
prerequisites.get_app()
prerequisites.get_compiled_app()
if not prerequisites.check_db_initialized():
return
with model.Model.get_db_engine().connect() as connection:

View File

@ -1316,6 +1316,7 @@ class State(BaseState):
Returns:
The list of events to queue for on load handling.
"""
# Do not app.compile_()! It should be already compiled by now.
app = getattr(prerequisites.get_app(), constants.CompileVars.APP)
load_events = app.get_load_events(self.router.page.path)
if not load_events and self.is_hydrated:
@ -1364,6 +1365,7 @@ class StateProxy(wrapt.ObjectProxy):
state_instance: The state instance to proxy.
"""
super().__init__(state_instance)
# compile is not relevant to backend logic
self._self_app = getattr(prerequisites.get_app(), constants.CompileVars.APP)
self._self_substate_path = state_instance.get_full_name().split(".")
self._self_actx = None

View File

@ -165,7 +165,7 @@ class AppHarness:
# reset rx.State subclasses
State.class_subclasses.clear()
# self.app_module.app.
self.app_module = reflex.utils.prerequisites.get_app(reload=True)
self.app_module = reflex.utils.prerequisites.get_compiled_app(reload=True)
self.app_instance = self.app_module.app
if isinstance(self.app_instance.state_manager, StateManagerRedis):
# Create our own redis connection for testing.

View File

@ -160,7 +160,7 @@ def run_backend(
import uvicorn
config = get_config()
app_module = f"{config.app_name}.{config.app_name}:{constants.CompileVars.APP}"
app_module = f"reflex.app_module_for_backend:{constants.CompileVars.APP}"
# Create a .nocompile file to skip compile for backend.
if os.path.exists(constants.Dirs.WEB):
@ -196,7 +196,7 @@ def run_backend_prod(
config = get_config()
RUN_BACKEND_PROD = f"gunicorn --worker-class {config.gunicorn_worker_class} --preload --timeout {config.timeout} --log-level critical".split()
RUN_BACKEND_PROD_WINDOWS = f"uvicorn --timeout-keep-alive {config.timeout}".split()
app_module = f"{config.app_name}.{config.app_name}:{constants.CompileVars.APP}"
app_module = f"reflex.app_module_for_backend:{constants.CompileVars.APP}"
command = (
[
*RUN_BACKEND_PROD_WINDOWS,

View File

@ -56,7 +56,7 @@ def export(
# Update some parameters for export
prerequisites.update_next_config(export=True)
# Ensure module can be imported and app.compile() is called.
prerequisites.get_app()
prerequisites.get_compiled_app()
# Set up .web directory and install frontend dependencies.
build.setup_frontend(Path.cwd())

View File

@ -160,9 +160,24 @@ def get_app(reload: bool = False) -> ModuleType:
app = __import__(module, fromlist=(constants.CompileVars.APP,))
if reload:
importlib.reload(app)
return app
def get_compiled_app(reload: bool = False) -> ModuleType:
"""Get the app module based on the default config after first compiling it.
Args:
reload: Re-import the app module from disk
Returns:
The compiled app based on the default config.
"""
app_module = get_app(reload=reload)
getattr(app_module, constants.CompileVars.APP).compile_()
return app_module
def get_redis() -> Redis | None:
"""Get the redis client.

View File

@ -1213,7 +1213,7 @@ def test_app_wrap_compile_theme(compilable_app):
"""
app, web_dir = compilable_app
app.theme = rdxt.theme(accent_color="plum")
app.compile()
app.compile_()
app_js_contents = (web_dir / "pages" / "_app.js").read_text()
app_js_lines = [
line.strip() for line in app_js_contents.splitlines() if line.strip()
@ -1263,7 +1263,7 @@ def test_app_wrap_priority(compilable_app):
return Fragment1.create(Fragment3.create())
app.add_page(page)
app.compile()
app.compile_()
app_js_contents = (web_dir / "pages" / "_app.js").read_text()
app_js_lines = [
line.strip() for line in app_js_contents.splitlines() if line.strip()

View File

@ -1590,7 +1590,11 @@ def mock_app(monkeypatch, state_manager: StateManager) -> rx.App:
app.state = TestState
app._state_manager = state_manager
app.event_namespace.emit = AsyncMock() # type: ignore
monkeypatch.setattr(prerequisites, "get_app", lambda: app_module)
def _mock_get_app(*args, **kwargs):
return app_module
monkeypatch.setattr(prerequisites, "get_app", _mock_get_app)
return app

View File

@ -21,7 +21,7 @@ def test_app_harness(tmp_path):
app = rx.App(state=State)
app.add_page(lambda: rx.text("Basic App"), route="/", title="index")
app.compile()
app.compile_()
with AppHarness.create(
root=tmp_path,