run.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. import inspect
  2. import logging
  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. favicon: Optional[str] = None,
  16. dark: Optional[bool] = False,
  17. binding_refresh_interval: float = 0.1,
  18. show: bool = True,
  19. reload: bool = True,
  20. uvicorn_logging_level: str = 'warning',
  21. uvicorn_reload_dirs: str = '.',
  22. uvicorn_reload_includes: str = '*.py',
  23. uvicorn_reload_excludes: str = '.*, .py[cod], .sw.*, ~*',
  24. exclude: str = '',
  25. ) -> None:
  26. '''ui.run
  27. You can call `ui.run()` with optional arguments:
  28. :param host: start server with this host (default: `'0.0.0.0'`)
  29. :param port: use this port (default: `8080`)
  30. :param title: page title (default: `'NiceGUI'`, can be overwritten per page)
  31. :param favicon: relative filepath to a favicon (default: `None`, NiceGUI icon will be used)
  32. :param dark: whether to use Quasar's dark mode (default: `False`, use `None` for "auto" mode)
  33. :param binding_refresh_interval: time between binding updates (default: `0.1` seconds, bigger is more CPU friendly)
  34. :param show: automatically open the UI in a browser tab (default: `True`)
  35. :param reload: automatically reload the UI on file changes (default: `True`)
  36. :param uvicorn_logging_level: logging level for uvicorn server (default: `'warning'`)
  37. :param uvicorn_reload_dirs: string with comma-separated list for directories to be monitored (default is current working directory only)
  38. :param uvicorn_reload_includes: string with comma-separated list of glob-patterns which trigger reload on modification (default: `'.py'`)
  39. :param uvicorn_reload_excludes: string with comma-separated list of glob-patterns which should be ignored for reload (default: `'.*, .py[cod], .sw.*, ~*'`)
  40. :param exclude: comma-separated string to exclude elements (with corresponding JavaScript libraries) to save bandwidth
  41. (possible entries: chart, colors, interactive_image, joystick, keyboard, log, scene, upload, table)
  42. The environment variables `HOST` and `PORT` can also be used to configure NiceGUI.
  43. To avoid the potentially costly import of Matplotlib, you set the environment variable `MATPLOTLIB=false`.
  44. This will make `ui.plot` and `ui.line_plot` unavailable.
  45. '''
  46. globals.host = host
  47. globals.port = port
  48. globals.reload = reload
  49. globals.title = title
  50. globals.favicon = favicon
  51. globals.dark = dark
  52. globals.binding_refresh_interval = binding_refresh_interval
  53. globals.excludes = [e.strip() for e in exclude.split(',')]
  54. if inspect.stack()[-2].filename.endswith('spawn.py'):
  55. return
  56. if show:
  57. webbrowser.open(f'http://{host if host != "0.0.0.0" else "127.0.0.1"}:{port}/')
  58. def split_args(args: str) -> List[str]:
  59. return [a.strip() for a in args.split(',')]
  60. # NOTE: The following lines are basically a copy of `uvicorn.run`, but keep a reference to the `server`.
  61. config = uvicorn.Config(
  62. 'nicegui:app' if reload else globals.app,
  63. host=host,
  64. port=port,
  65. reload=reload,
  66. reload_includes=split_args(uvicorn_reload_includes) if reload else None,
  67. reload_excludes=split_args(uvicorn_reload_excludes) if reload else None,
  68. reload_dirs=split_args(uvicorn_reload_dirs) if reload else None,
  69. log_level=uvicorn_logging_level,
  70. )
  71. globals.server = uvicorn.Server(config=config)
  72. if (reload or config.workers > 1) and not isinstance(config.app, str):
  73. logging.warning('You must pass the application as an import string to enable "reload" or "workers".')
  74. sys.exit(1)
  75. if config.should_reload:
  76. sock = config.bind_socket()
  77. ChangeReload(config, target=globals.server.run, sockets=[sock]).run()
  78. elif config.workers > 1:
  79. sock = config.bind_socket()
  80. Multiprocess(config, target=globals.server.run, sockets=[sock]).run()
  81. else:
  82. globals.server.run()
  83. if config.uds:
  84. os.remove(config.uds) # pragma: py-win32
  85. if not globals.server.started and not config.should_reload and config.workers == 1:
  86. sys.exit(STARTUP_FAILURE)