run.py 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. import logging
  2. import multiprocessing
  3. import os
  4. import sys
  5. import webbrowser
  6. from typing import List, Optional, Tuple, Union
  7. import uvicorn
  8. from uvicorn.main import STARTUP_FAILURE
  9. from uvicorn.supervisors import ChangeReload, Multiprocess
  10. from . import globals, standalone_mode
  11. def run(*,
  12. host: str = '0.0.0.0',
  13. port: int = 8080,
  14. title: str = 'NiceGUI',
  15. viewport: str = 'width=device-width, initial-scale=1',
  16. favicon: Optional[str] = None,
  17. dark: Optional[bool] = False,
  18. binding_refresh_interval: float = 0.1,
  19. show: bool = True,
  20. standalone: bool = False,
  21. fullscreen: Union[bool, Tuple[int, int]] = False,
  22. reload: bool = True,
  23. uvicorn_logging_level: str = 'warning',
  24. uvicorn_reload_dirs: str = '.',
  25. uvicorn_reload_includes: str = '*.py',
  26. uvicorn_reload_excludes: str = '.*, .py[cod], .sw.*, ~*',
  27. exclude: str = '',
  28. tailwind: bool = True,
  29. **kwargs,
  30. ) -> None:
  31. '''ui.run
  32. You can call `ui.run()` with optional arguments:
  33. :param host: start server with this host (default: `'0.0.0.0'`)
  34. :param port: use this port (default: `8080`)
  35. :param title: page title (default: `'NiceGUI'`, can be overwritten per page)
  36. :param viewport: page meta viewport content (default: `'width=device-width, initial-scale=1'`, can be overwritten per page)
  37. :param favicon: relative filepath or absolute URL to a favicon (default: `None`, NiceGUI icon will be used)
  38. :param dark: whether to use Quasar's dark mode (default: `False`, use `None` for "auto" mode)
  39. :param binding_refresh_interval: time between binding updates (default: `0.1` seconds, bigger is more CPU friendly)
  40. :param show: automatically open the UI in a browser tab (default: `True`)
  41. :param standalone: open the UI in a standalone window (default: `False`, accepts size as tuple or True (800, 600), deactivates `show`, automatically finds an open port)
  42. :param fullscreen: open the UI in a fullscreen, standalone window (default: `False`, also activates `standalone`)
  43. :param reload: automatically reload the UI on file changes (default: `True`)
  44. :param uvicorn_logging_level: logging level for uvicorn server (default: `'warning'`)
  45. :param uvicorn_reload_dirs: string with comma-separated list for directories to be monitored (default is current working directory only)
  46. :param uvicorn_reload_includes: string with comma-separated list of glob-patterns which trigger reload on modification (default: `'.py'`)
  47. :param uvicorn_reload_excludes: string with comma-separated list of glob-patterns which should be ignored for reload (default: `'.*, .py[cod], .sw.*, ~*'`)
  48. :param exclude: comma-separated string to exclude elements (with corresponding JavaScript libraries) to save bandwidth
  49. (possible entries: aggrid, audio, chart, colors, interactive_image, joystick, keyboard, log, markdown, mermaid, plotly, scene, video)
  50. :param tailwind: whether to use Tailwind (experimental, default: `True`)
  51. :param kwargs: additional keyword arguments are passed to `uvicorn.run`
  52. '''
  53. globals.ui_run_has_been_called = True
  54. globals.host = host
  55. globals.port = port
  56. globals.reload = reload
  57. globals.title = title
  58. globals.viewport = viewport
  59. globals.favicon = favicon
  60. globals.dark = dark
  61. globals.binding_refresh_interval = binding_refresh_interval
  62. globals.excludes = [e.strip() for e in exclude.split(',')]
  63. globals.tailwind = tailwind
  64. if multiprocessing.current_process().name != 'MainProcess':
  65. return
  66. if fullscreen:
  67. standalone = True
  68. if standalone:
  69. show = False
  70. width, height = (800, 600) if standalone is True else standalone
  71. standalone_mode.activate(f'http://localhost:{port}', title, width, height, fullscreen)
  72. if show:
  73. webbrowser.open(f'http://{host if host != "0.0.0.0" else "127.0.0.1"}:{port}/')
  74. def split_args(args: str) -> List[str]:
  75. return [a.strip() for a in args.split(',')]
  76. # NOTE: The following lines are basically a copy of `uvicorn.run`, but keep a reference to the `server`.
  77. config = uvicorn.Config(
  78. 'nicegui:app' if reload else globals.app,
  79. host=host,
  80. port=port,
  81. reload=reload,
  82. reload_includes=split_args(uvicorn_reload_includes) if reload else None,
  83. reload_excludes=split_args(uvicorn_reload_excludes) if reload else None,
  84. reload_dirs=split_args(uvicorn_reload_dirs) if reload else None,
  85. log_level=uvicorn_logging_level,
  86. **kwargs,
  87. )
  88. globals.server = uvicorn.Server(config=config)
  89. if (reload or config.workers > 1) and not isinstance(config.app, str):
  90. logging.warning('You must pass the application as an import string to enable "reload" or "workers".')
  91. sys.exit(1)
  92. if config.should_reload:
  93. sock = config.bind_socket()
  94. ChangeReload(config, target=globals.server.run, sockets=[sock]).run()
  95. elif config.workers > 1:
  96. sock = config.bind_socket()
  97. Multiprocess(config, target=globals.server.run, sockets=[sock]).run()
  98. else:
  99. globals.server.run()
  100. if config.uds:
  101. os.remove(config.uds) # pragma: py-win32
  102. if not globals.server.started and not config.should_reload and config.workers == 1:
  103. sys.exit(STARTUP_FAILURE)