瀏覽代碼

introduce ui.run() to start server with or without reloading and other configuration

Falko Schindler 3 年之前
父節點
當前提交
9d013b61af
共有 4 個文件被更改,包括 74 次插入33 次删除
  1. 43 0
      nicegui/config.py
  2. 9 33
      nicegui/nicegui.py
  3. 20 0
      nicegui/run.py
  4. 2 0
      nicegui/ui.py

+ 43 - 0
nicegui/config.py

@@ -0,0 +1,43 @@
+from pydantic import BaseModel
+import inspect
+import ast
+import os
+
+class Config(BaseModel):
+
+    # NOTE: should be in sync with ui.run arguments
+    host: str = '0.0.0.0'
+    port: int = 80
+    title: str = 'NiceGUI'
+    favicon: str = 'favicon.png'
+    reload: bool = True
+    show: bool = True
+
+
+for f in reversed(inspect.stack()):
+    if os.path.basename(f.filename) not in ('<string>', 'spawn.py', 'runpy.py'):
+        filepath = f.filename
+        break
+else:
+    raise Exception("Could not find main script in stacktrace")
+
+with open(filepath) as f:
+    source = f.read()
+
+for node in ast.parse(source).body:
+    try:
+        func = node.value.func
+        if func.value.id == 'ui' and func.attr == 'run':
+            args = {
+                keyword.arg: keyword.value.value
+                for keyword in node.value.keywords
+            }
+            config = Config(**args)
+            break
+    except AttributeError:
+        continue
+else:
+    raise Exception('Could not find ui.run() command')
+
+os.environ['HOST'] = config.host
+os.environ['PORT'] = str(config.port)

+ 9 - 33
nicegui/nicegui.py

@@ -1,39 +1,17 @@
 #!/usr/bin/env python3
 from typing import Awaitable, Callable
-import os 
-host = os.getenv('HOST', '0.0.0.0')
-port = int(os.getenv('PORT', '80'))
-os.environ['HOST'] = host
-os.environ['PORT']= str(port)
-import justpy as jp
-import uvicorn
-import sys
-import inspect
-import webbrowser
-from pygments.formatters import HtmlFormatter
-import binding
 import asyncio
-from .ui import Ui
-from .timer import Timer
+import binding
+from pygments.formatters import HtmlFormatter
+import os
+from .ui import Ui  # NOTE: before justpy
+import justpy as jp
 from .elements.element import Element
-import atexit
-
+from .timer import Timer
 
 os.environ["STATIC_DIRECTORY"] = os.path.dirname(os.path.realpath(__file__)) + '/static'
 os.environ["TEMPLATES_DIRECTORY"] = os.environ["STATIC_DIRECTORY"] + '/templates'
 
-if os.getenv('RELOAD', 'true').lower() in ('true', 't', 'y', 'yes', '1'):
-    if not inspect.stack()[-2].filename.endswith('spawn.py'):
-        webbrowser.open(f'http://{host}:{port}/')
-        uvicorn.run('nicegui:app', host=host, port=port, lifespan='on', reload=True)
-        sys.exit()
-else:
-    def start_web():
-        webbrowser.open(f'http://{host}:{port}/')
-        uvicorn.run(jp.app, host=host, port=port, lifespan='on')
-       
-    atexit.register(start_web)
-
 @jp.SetRoute('/file')
 def get_file(request):
     wp = jp.WebPage()
@@ -41,7 +19,7 @@ def get_file(request):
         wp.html = f.read()
     return wp
 
-wp = jp.QuasarPage(delete_flag=False, title='NiceGUI', favicon='favicon.png')
+wp = jp.QuasarPage(delete_flag=False, title=Ui.config.title, favicon=Ui.config.favicon)
 wp.tailwind = True  # use Tailwind classes instead of Quasars
 wp.css = HtmlFormatter().get_style_defs('.codehilite')
 wp.head_html += '<script>confirm = () => true;</script>\n'  # avoid confirmation dialog for reload
@@ -64,9 +42,8 @@ tasks = []
 
 @jp.app.on_event('startup')
 def startup():
-    global tasks
-    tasks += [create_task(t) for t in Timer.tasks]
-    tasks += [create_task(t) for t in Ui.startup_tasks if isinstance(t, Awaitable)]
+    tasks.extend(create_task(t) for t in Timer.tasks)
+    tasks.extend(create_task(t) for t in Ui.startup_tasks if isinstance(t, Awaitable))
     [t() for t in Ui.startup_tasks if isinstance(t, Callable)]
     jp.run_task(binding_loop())
 
@@ -74,7 +51,6 @@ def startup():
 def shutdown():
     [create_task(t) for t in Ui.shutdown_tasks if isinstance(t, Awaitable)]
     [t() for t in Ui.shutdown_tasks if isinstance(t, Callable)]
-    # # also abort all running startup tasks
     [t.cancel() for t in tasks]
 
 Element.wp = wp

+ 20 - 0
nicegui/run.py

@@ -0,0 +1,20 @@
+import inspect
+import sys
+import webbrowser
+import uvicorn
+from .config import config  # NOTE: before justpy
+import justpy as jp
+
+if 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)
+    sys.exit()
+
+def run(self, *, host='0.0.0.0', port=80, title='NiceGUI', favicon='favicon.png', reload=True, show=True):
+
+    if reload == False:  # NOTE: in case reload == True we already started uvicorn above
+        if show:
+            webbrowser.open(f'http://{host}:{port}/')
+        uvicorn.run(jp.app, host=host, port=port, lifespan='on')

+ 2 - 0
nicegui/ui.py

@@ -3,6 +3,8 @@ from typing import Awaitable, Callable, List, Union
 
 class Ui:
 
+    from .run import run, config  # NOTE: before justpy
+
     from .elements.button import Button as button
     from .elements.checkbox import Checkbox as checkbox
     from .elements.custom_example import CustomExample as custom_example