Ver Fonte

move app state into app

Falko Schindler há 1 ano atrás
pai
commit
25be2973a8
6 ficheiros alterados com 53 adições e 25 exclusões
  1. 46 1
      nicegui/app.py
  2. 3 2
      nicegui/elements/timer.py
  3. 0 10
      nicegui/globals.py
  4. 1 1
      nicegui/native_mode.py
  5. 2 10
      nicegui/nicegui.py
  6. 1 1
      nicegui/run_executor.py

+ 46 - 1
nicegui/app.py

@@ -1,4 +1,5 @@
 import inspect
+from enum import Enum
 from pathlib import Path
 from typing import Any, Awaitable, Callable, List, Optional, Union
 
@@ -13,6 +14,13 @@ from .observables import ObservableSet
 from .storage import Storage
 
 
+class State(Enum):
+    STOPPED = 0
+    STARTING = 1
+    STARTED = 2
+    STOPPING = 3
+
+
 class App(FastAPI):
 
     def __init__(self, **kwargs) -> None:
@@ -20,6 +28,7 @@ class App(FastAPI):
         self.native = Native()
         self.storage = Storage()
         self.urls = ObservableSet()
+        self.state: State = State.STOPPED
 
         self._startup_handlers: List[Union[Callable[..., Any], Awaitable]] = []
         self._shutdown_handlers: List[Union[Callable[..., Any], Awaitable]] = []
@@ -27,6 +36,42 @@ class App(FastAPI):
         self._disconnect_handlers: List[Union[Callable[..., Any], Awaitable]] = []
         self._exception_handlers: List[Callable[..., Any]] = [log.exception]
 
+    @property
+    def is_starting(self) -> bool:
+        """Return whether NiceGUI is starting."""
+        return self.state == State.STARTING
+
+    @property
+    def is_started(self) -> bool:
+        """Return whether NiceGUI is started."""
+        return self.state == State.STARTED
+
+    @property
+    def is_stopping(self) -> bool:
+        """Return whether NiceGUI is stopping."""
+        return self.state == State.STOPPING
+
+    @property
+    def is_stopped(self) -> bool:
+        """Return whether NiceGUI is stopped."""
+        return self.state == State.STOPPED
+
+    def start(self) -> None:
+        """Start NiceGUI. (For internal use only.)"""
+        self.state = State.STARTING
+        with globals.index_client:
+            for t in self._startup_handlers:
+                helpers.safe_invoke(t)
+        self.state = State.STARTED
+
+    def stop(self) -> None:
+        """Stop NiceGUI. (For internal use only.)"""
+        self.state = State.STOPPING
+        with globals.index_client:
+            for t in self._shutdown_handlers:
+                helpers.safe_invoke(t)
+        self.state = State.STOPPED
+
     def on_connect(self, handler: Union[Callable, Awaitable]) -> None:
         """Called every time a new client connects to NiceGUI.
 
@@ -46,7 +91,7 @@ class App(FastAPI):
 
         Needs to be called before `ui.run()`.
         """
-        if globals.state == globals.State.STARTED:
+        if self.is_started:
             raise RuntimeError('Unable to register another startup handler. NiceGUI has already been started.')
         self._startup_handlers.append(handler)
 

+ 3 - 2
nicegui/elements/timer.py

@@ -36,7 +36,7 @@ class Timer(Element, component='timer.js'):
         self._is_canceled: bool = False
 
         coroutine = self._run_once if once else self._run_in_loop
-        if globals.state == globals.State.STARTED:
+        if globals.app.is_started:
             background_tasks.create(coroutine(), name=str(callback))
         else:
             globals.app.on_startup(coroutine)
@@ -116,7 +116,8 @@ class Timer(Element, component='timer.js'):
             self.is_deleted or
             self.client.id not in globals.clients or
             self._is_canceled or
-            globals.state in {globals.State.STOPPING, globals.State.STOPPED}
+            globals.app.is_stopping or
+            globals.app.is_stopped
         )
 
     def _cleanup(self) -> None:

+ 0 - 10
nicegui/globals.py

@@ -3,7 +3,6 @@ from __future__ import annotations
 import asyncio
 import os
 from contextlib import contextmanager
-from enum import Enum
 from pathlib import Path
 from typing import TYPE_CHECKING, Dict, Iterator, List, Literal, Optional, Set, Union
 
@@ -17,19 +16,10 @@ if TYPE_CHECKING:
     from .language import Language
     from .slot import Slot
 
-
-class State(Enum):
-    STOPPED = 0
-    STARTING = 1
-    STARTED = 2
-    STOPPING = 3
-
-
 app: App
 sio: AsyncServer
 server: Server
 loop: Optional[asyncio.AbstractEventLoop] = None
-state: State = State.STOPPED
 ui_run_has_been_called: bool = False
 optional_features: Set[str] = set()
 

+ 1 - 1
nicegui/native_mode.py

@@ -98,7 +98,7 @@ def activate(host: str, port: int, title: str, width: int, height: int, fullscre
         while process.is_alive():
             time.sleep(0.1)
         globals.server.should_exit = True
-        while globals.state != globals.State.STOPPED:
+        while not globals.app.is_stopped:
             time.sleep(0.1)
         _thread.interrupt_main()
 

+ 2 - 10
nicegui/nicegui.py

@@ -91,16 +91,12 @@ def handle_startup(with_welcome_message: bool = True) -> None:
             app.add_route('/favicon.ico', lambda _: favicon.get_favicon_response())
     else:
         app.add_route('/favicon.ico', lambda _: FileResponse(Path(__file__).parent / 'static' / 'favicon.ico'))
-    globals.state = globals.State.STARTING
     globals.loop = asyncio.get_running_loop()
-    with globals.index_client:
-        for t in app._startup_handlers:
-            safe_invoke(t)
+    globals.app.start()
     background_tasks.create(binding.refresh_loop(), name='refresh bindings')
     background_tasks.create(outbox.loop(), name='send outbox')
     background_tasks.create(prune_clients(), name='prune clients')
     background_tasks.create(prune_slot_stacks(), name='prune slot stacks')
-    globals.state = globals.State.STARTED
     if with_welcome_message:
         background_tasks.create(welcome.print_message())
     if globals.air:
@@ -112,12 +108,8 @@ async def handle_shutdown() -> None:
     """Handle the shutdown event."""
     if app.native.main_window:
         app.native.main_window.signal_server_shutdown()
-    globals.state = globals.State.STOPPING
-    with globals.index_client:
-        for t in app._shutdown_handlers:
-            safe_invoke(t)
+    globals.app.stop()
     run_executor.tear_down()
-    globals.state = globals.State.STOPPED
     if globals.air:
         await globals.air.disconnect()
 

+ 1 - 1
nicegui/run_executor.py

@@ -11,7 +11,7 @@ thread_pool = ThreadPoolExecutor()
 
 
 async def _run(executor: Any, callback: Callable, *args: Any, **kwargs: Any) -> Any:
-    if globals.state == globals.State.STOPPING:
+    if globals.app.is_stopping:
         return
     try:
         loop = asyncio.get_running_loop()