Procházet zdrojové kódy

experiment with module for global state

Falko Schindler před 3 roky
rodič
revize
5e589ace48

+ 4 - 3
main.py

@@ -2,16 +2,17 @@
 from nicegui import ui
 from contextlib import contextmanager
 import inspect
-from nicegui.elements.markdown import Markdown
-from nicegui.elements.element import Element
 import sys
 from typing import Union
 import docutils.core
 import re
 import asyncio
+from nicegui.elements.markdown import Markdown
+from nicegui.elements.element import Element
+from nicegui.globals import page_stack
 
 # add docutils css to webpage
-Element.wp_stack[0].head_html += docutils.core.publish_parts('', writer_name='html')['stylesheet']
+page_stack[0].head_html += docutils.core.publish_parts('', writer_name='html')['stylesheet']
 
 @contextmanager
 def example(content: Union[Element, str]):

+ 3 - 0
nicegui/config.py

@@ -2,6 +2,7 @@ from pydantic import BaseModel
 import inspect
 import ast
 import os
+from . import globals
 
 class Config(BaseModel):
 
@@ -58,3 +59,5 @@ os.environ['HOST'] = config.host
 os.environ['PORT'] = str(config.port)
 os.environ["STATIC_DIRECTORY"] = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'static')
 os.environ["TEMPLATES_DIRECTORY"] = os.path.join(os.environ["STATIC_DIRECTORY"], 'templates')
+
+globals.config = config

+ 3 - 5
nicegui/elements/element.py

@@ -1,21 +1,19 @@
 import justpy as jp
 from binding.binding import BindableProperty
+from ..globals import view_stack, page_stack
 
 class Element:
 
-    wp_stack = []
-    view_stack = []
-
     visible = BindableProperty
 
     def __init__(self,
                  view: jp.HTMLBaseComponent,
                  ):
 
-        self.parent_view = self.view_stack[-1]
+        self.parent_view = view_stack[-1]
         self.parent_view.add(view)
         self.view = view
-        self.page = self.wp_stack[-1]
+        self.page = page_stack[-1]
         self.view.add_page(self.page)
 
         self.visible = True

+ 3 - 2
nicegui/elements/group.py

@@ -1,12 +1,13 @@
 from .element import Element
+from ..globals import view_stack
 
 class Group(Element):
 
     def __enter__(self):
 
-        self.view_stack.append(self.view)
+        view_stack.append(self.view)
         return self
 
     def __exit__(self, *_):
 
-        self.view_stack.pop()
+        view_stack.pop()

+ 7 - 10
nicegui/elements/page.py

@@ -1,13 +1,10 @@
 import justpy as jp
 from typing import Optional
 from pygments.formatters import HtmlFormatter
-from .element import Element
+from ..globals import config, page_stack, view_stack
 
 class Page(jp.QuasarPage):
 
-    default_title: str
-    default_favicon: str
-
     def __init__(self, route: str, title: Optional[str] = None, favicon: Optional[str] = None):
         """Page
 
@@ -18,8 +15,8 @@ class Page(jp.QuasarPage):
         super().__init__()
 
         self.delete_flag = False
-        self.title = title or self.default_title
-        self.favicon = favicon or self.default_favicon
+        self.title = title or config.title
+        self.favicon = favicon or config.favicon
 
         self.tailwind = True  # use Tailwind classes instead of Quasars
         self.css = HtmlFormatter().get_style_defs('.codehilite')
@@ -35,10 +32,10 @@ class Page(jp.QuasarPage):
         jp.Route(route, lambda: self)
 
     def __enter__(self):
-        Element.wp_stack.append(self)
-        Element.view_stack.append(self.view)
+        page_stack.append(self)
+        view_stack.append(self.view)
         return self
 
     def __exit__(self, *_):
-        Element.wp_stack.pop()
-        Element.view_stack.pop()
+        page_stack.pop()
+        view_stack.pop()

+ 3 - 2
nicegui/elements/scene.py

@@ -4,6 +4,7 @@ from .element import Element
 from .custom_view import CustomView
 from .page import Page
 from .scene_object3d import Object3D
+from ..globals import view_stack
 
 class SceneView(CustomView):
 
@@ -59,14 +60,14 @@ class Scene(Element):
         super().__init__(SceneView(width=width, height=height, on_click=on_click))
 
     def __enter__(self):
-        self.view_stack.append(self.view)
+        view_stack.append(self.view)
         scene = self.view.objects.get('scene', SceneObject(self.view, self.page))
         Object3D.stack.clear()
         Object3D.stack.append(scene)
         return self
 
     def __exit__(self, *_):
-        self.view_stack.pop()
+        view_stack.pop()
 
 class SceneObject:
 

+ 11 - 0
nicegui/globals.py

@@ -0,0 +1,11 @@
+from typing import TYPE_CHECKING
+if TYPE_CHECKING:
+    from starlette.applications import Starlette
+    import justpy as jp
+    from .config import Config
+    from .elements.page import Page
+
+app: 'Starlette'
+config: 'Config'
+page_stack: list['Page'] = []
+view_stack: list['jp.HTMLBaseComponent'] = []

+ 3 - 4
nicegui/nicegui.py

@@ -6,6 +6,7 @@ import binding
 from .ui import Ui  # NOTE: before justpy
 import justpy as jp
 from .timer import Timer
+from . import globals
 
 
 async def binding_loop():
@@ -33,11 +34,9 @@ def shutdown():
     [t.cancel() for t in tasks]
 
 
-app = jp.app
-ui = Ui(app)
+app = globals.app = jp.app
+ui = Ui()
 
-ui.page.default_title = ui.config.title
-ui.page.default_favicon = ui.config.favicon
 page = ui.page('/')
 page.__enter__()
 jp.justpy(lambda: page, start_server=False)

+ 4 - 0
nicegui/routes.py

@@ -0,0 +1,4 @@
+from . import globals
+
+def add_route(self, route):
+    globals.app.routes.insert(0, route)

+ 7 - 8
nicegui/run.py

@@ -2,19 +2,18 @@ import inspect
 import sys
 import webbrowser
 import uvicorn
-from .config import config  # NOTE: before justpy
-import justpy as jp
+from . import globals
 
-if not config.interactive and config.reload and not inspect.stack()[-2].filename.endswith('spawn.py'):
+if not globals.config.interactive and globals.config.reload and not inspect.stack()[-2].filename.endswith('spawn.py'):
 
-    if config.show:
-        webbrowser.open(f'http://{config.host}:{config.port}/')
-    uvicorn.run('nicegui:app', host=config.host, port=config.port, lifespan='on', reload=True)
+    if globals.config.show:
+        webbrowser.open(f'http://{globals.config.host}:{globals.config.port}/')
+    uvicorn.run('nicegui:app', host=globals.config.host, port=globals.config.port, lifespan='on', reload=True)
     sys.exit()
 
 def run(self, *, host='0.0.0.0', port=80, title='NiceGUI', favicon='favicon.ico', reload=True, show=True):
 
-    if config.interactive or reload == False:  # NOTE: if reload == True we already started uvicorn above
+    if globals.config.interactive or reload == False:  # NOTE: if reload == True we already started uvicorn above
         if show:
             webbrowser.open(f'http://{host if host != "0.0.0.0" else "127.0.0.1"}:{port}/')
-        uvicorn.run(jp.app, host=host, port=port, lifespan='on')
+        uvicorn.run(globals.app, host=host, port=port, lifespan='on')

+ 2 - 2
nicegui/timer.py

@@ -3,7 +3,7 @@ import time
 import traceback
 from typing import Awaitable, Callable, Union
 from binding import BindableProperty
-from .elements.element import Element
+from .globals import view_stack
 from .utils import handle_exceptions, handle_awaitable
 
 class Timer:
@@ -25,7 +25,7 @@ class Timer:
         :param once: whether the callback is only executed once after a delay specified by `interval`; default is `False`
         """
 
-        parent = Element.view_stack[-1]
+        parent = view_stack[-1]
         self.active = active
 
         async def timeout():

+ 3 - 7
nicegui/ui.py

@@ -1,6 +1,7 @@
 class Ui:
 
-    from .run import run, config  # NOTE: before justpy
+    from .config import config  # NOTE: before run
+    from .run import run  # NOTE: before justpy
 
     from .elements.button import Button as button
     from .elements.checkbox import Checkbox as checkbox
@@ -39,9 +40,4 @@ class Ui:
 
     from .lifecycle import startup_tasks, on_startup, shutdown_tasks, on_shutdown
 
-    def __init__(self, app) -> None:
-        self.app = app
-        
-
-    def add_route(self, route):
-        self.app.routes.insert(0, route)
+    from .routes import add_route