Browse Source

remove server from globals

Falko Schindler 1 year ago
parent
commit
b7756b2bf9
7 changed files with 51 additions and 34 deletions
  1. 2 0
      nicegui/__init__.py
  2. 2 1
      nicegui/app.py
  3. 0 2
      nicegui/globals.py
  4. 2 1
      nicegui/native_mode.py
  5. 6 28
      nicegui/run.py
  6. 37 0
      nicegui/server.py
  7. 2 2
      tests/screen.py

+ 2 - 0
nicegui/__init__.py

@@ -6,6 +6,7 @@ from .awaitable_response import AwaitableResponse
 from .client import Client
 from .logging import log
 from .nicegui import app
+from .server import Server
 from .tailwind import Tailwind
 from .version import __version__
 
@@ -20,6 +21,7 @@ __all__ = [
     'log',
     'optional_features',
     'run',
+    'Server',
     'Tailwind',
     'ui',
     '__version__',

+ 2 - 1
nicegui/app.py

@@ -12,6 +12,7 @@ from .client import Client
 from .logging import log
 from .native import Native
 from .observables import ObservableSet
+from .server import Server
 from .storage import Storage
 
 
@@ -126,7 +127,7 @@ class App(FastAPI):
         if self.native.main_window:
             self.native.main_window.destroy()
         else:
-            globals.server.should_exit = True
+            Server.instance.should_exit = True
 
     def add_static_files(self, url_path: str, local_directory: Union[str, Path]) -> None:
         """Add a directory of static files.

+ 0 - 2
nicegui/globals.py

@@ -5,7 +5,6 @@ from pathlib import Path
 from typing import TYPE_CHECKING, Dict, List, Literal, Optional, Union
 
 from socketio import AsyncServer
-from uvicorn import Server
 
 if TYPE_CHECKING:
     from .app import App
@@ -13,7 +12,6 @@ if TYPE_CHECKING:
 
 app: App
 sio: AsyncServer
-server: Server
 loop: Optional[asyncio.AbstractEventLoop] = None
 ui_run_has_been_called: bool = False
 

+ 2 - 1
nicegui/native_mode.py

@@ -13,6 +13,7 @@ from typing import Any, Callable, Dict, List, Tuple
 
 from . import globals, helpers, native, optional_features  # pylint: disable=redefined-builtin
 from .logging import log
+from .server import Server
 
 try:
     with warnings.catch_warnings():
@@ -97,7 +98,7 @@ def activate(host: str, port: int, title: str, width: int, height: int, fullscre
     def check_shutdown() -> None:
         while process.is_alive():
             time.sleep(0.1)
-        globals.server.should_exit = True
+        Server.instance.should_exit = True
         while not globals.app.is_stopped:
             time.sleep(0.1)
         _thread.interrupt_main()

+ 6 - 28
nicegui/run.py

@@ -1,47 +1,25 @@
 import multiprocessing
 import os
-import socket
 import sys
 from pathlib import Path
 from typing import Any, List, Literal, Optional, Tuple, Union
 
 import __main__
-import uvicorn
 from starlette.routing import Route
 from uvicorn.main import STARTUP_FAILURE
 from uvicorn.supervisors import ChangeReload, Multiprocess
 
 from . import native_mode  # pylint: disable=redefined-builtin
-from . import storage  # pylint: disable=redefined-builtin
 from . import air, globals, helpers  # pylint: disable=redefined-builtin
 from . import native as native_module
 from .client import Client
 from .language import Language
 from .logging import log
+from .server import CustomServerConfig, Server
 
 APP_IMPORT_STRING = 'nicegui:app'
 
 
-class CustomServerConfig(uvicorn.Config):
-    storage_secret: Optional[str] = None
-    method_queue: Optional[multiprocessing.Queue] = None
-    response_queue: Optional[multiprocessing.Queue] = None
-
-
-class Server(uvicorn.Server):
-
-    def run(self, sockets: Optional[List[socket.socket]] = None) -> None:
-        globals.server = self
-        assert isinstance(self.config, CustomServerConfig)
-        if self.config.method_queue is not None and self.config.response_queue is not None:
-            native_module.method_queue = self.config.method_queue
-            native_module.response_queue = self.config.response_queue
-            globals.app.native.main_window = native_module.WindowProxy()
-
-        storage.set_storage_secret(self.config.storage_secret)
-        super().run(sockets=sockets)
-
-
 def run(*,
         host: Optional[str] = None,
         port: int = 8080,
@@ -171,7 +149,7 @@ def run(*,
     config.storage_secret = storage_secret
     config.method_queue = native_module.method_queue if native else None
     config.response_queue = native_module.response_queue if native else None
-    globals.server = Server(config=config)
+    Server.create_singleton(config)
 
     if (reload or config.workers > 1) and not isinstance(config.app, str):
         log.warning('You must pass the application as an import string to enable "reload" or "workers".')
@@ -179,14 +157,14 @@ def run(*,
 
     if config.should_reload:
         sock = config.bind_socket()
-        ChangeReload(config, target=globals.server.run, sockets=[sock]).run()
+        ChangeReload(config, target=Server.instance.run, sockets=[sock]).run()
     elif config.workers > 1:
         sock = config.bind_socket()
-        Multiprocess(config, target=globals.server.run, sockets=[sock]).run()
+        Multiprocess(config, target=Server.instance.run, sockets=[sock]).run()
     else:
-        globals.server.run()
+        Server.instance.run()
     if config.uds:
         os.remove(config.uds)  # pragma: py-win32
 
-    if not globals.server.started and not config.should_reload and config.workers == 1:
+    if not Server.instance.started and not config.should_reload and config.workers == 1:
         sys.exit(STARTUP_FAILURE)

+ 37 - 0
nicegui/server.py

@@ -0,0 +1,37 @@
+from __future__ import annotations
+
+import multiprocessing
+import socket
+from typing import List, Optional
+
+import uvicorn
+
+from . import globals  # pylint: disable=redefined-builtin
+from . import storage  # pylint: disable=redefined-builtin
+from . import native as native_module
+
+
+class CustomServerConfig(uvicorn.Config):
+    storage_secret: Optional[str] = None
+    method_queue: Optional[multiprocessing.Queue] = None
+    response_queue: Optional[multiprocessing.Queue] = None
+
+
+class Server(uvicorn.Server):
+    instance: Server
+
+    @classmethod
+    def create_singleton(cls, config: CustomServerConfig) -> None:
+        """Create a singleton instance of the server."""
+        cls.instance = cls(config=config)
+
+    def run(self, sockets: Optional[List[socket.socket]] = None) -> None:
+        self.instance = self
+        assert isinstance(self.config, CustomServerConfig)
+        if self.config.method_queue is not None and self.config.response_queue is not None:
+            native_module.method_queue = self.config.method_queue
+            native_module.response_queue = self.config.response_queue
+            globals.app.native.main_window = native_module.WindowProxy()
+
+        storage.set_storage_secret(self.config.storage_secret)
+        super().run(sockets=sockets)

+ 2 - 2
tests/screen.py

@@ -12,7 +12,7 @@ from selenium.webdriver import ActionChains
 from selenium.webdriver.common.by import By
 from selenium.webdriver.remote.webelement import WebElement
 
-from nicegui import app, globals, ui  # pylint: disable=redefined-builtin
+from nicegui import Server, app, ui
 
 from .test_helpers import TEST_DIR
 
@@ -49,7 +49,7 @@ class Screen:
         """Stop the webserver."""
         self.close()
         self.caplog.clear()
-        globals.server.should_exit = True
+        Server.instance.should_exit = True
         if self.server_thread:
             self.server_thread.join()