run.py 4.5 KB

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