config.py 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. from dataclasses import dataclass
  2. from typing import Awaitable, Callable, Optional, Union
  3. import inspect
  4. import ast
  5. import os
  6. from . import globals
  7. @dataclass
  8. class Config():
  9. # NOTE: should be in sync with ui.run arguments
  10. host: str = os.environ.get('HOST', '0.0.0.0')
  11. port: int = int(os.environ.get('PORT', '8080'))
  12. title: str = 'NiceGUI'
  13. favicon: str = 'favicon.ico'
  14. dark: Optional[bool] = False
  15. reload: bool = True
  16. show: bool = True
  17. on_connect: Optional[Union[Callable, Awaitable]] = None
  18. uvicorn_logging_level: str = 'warning'
  19. uvicorn_reload_dirs: str = '.'
  20. uvicorn_reload_includes: str = '*'
  21. uvicorn_reload_excludes: str = '.*, .py[cod], .sw.*, ~*'
  22. main_page_classes: str = 'q-ma-md column items-start'
  23. binding_refresh_interval: float = 0.1
  24. interactive: bool = False
  25. excluded_endings = (
  26. '<string>',
  27. 'spawn.py',
  28. 'runpy.py',
  29. os.path.join('debugpy', 'server', 'cli.py'),
  30. os.path.join('debugpy', '__main__.py'),
  31. )
  32. for f in reversed(inspect.stack()):
  33. if not any(f.filename.endswith(ending) for ending in excluded_endings):
  34. filepath = f.filename
  35. break
  36. else:
  37. raise Exception("Could not find main script in stacktrace")
  38. try:
  39. with open(filepath) as f:
  40. source = f.read()
  41. except FileNotFoundError:
  42. print('Could not find main script. Starting interactive mode without auto-reload.', flush=True)
  43. config = Config(interactive=True)
  44. else:
  45. for node in ast.walk(ast.parse(source)):
  46. try:
  47. func = node.value.func
  48. if func.value.id == 'ui' and func.attr == 'run':
  49. args = {
  50. keyword.arg:
  51. keyword.value.n if isinstance(keyword.value, ast.Num) else
  52. keyword.value.s if isinstance(keyword.value, ast.Str) else
  53. keyword.value.value
  54. for keyword in node.value.keywords
  55. }
  56. config = Config(**args)
  57. break
  58. except AttributeError:
  59. continue
  60. else:
  61. print('Could not find and pre-evaluate ui.run(). Starting interactive mode without auto-reload.', flush=True)
  62. config = Config(interactive=True)
  63. os.environ['HOST'] = config.host
  64. os.environ['PORT'] = str(config.port)
  65. os.environ["STATIC_DIRECTORY"] = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'static')
  66. os.environ["TEMPLATES_DIRECTORY"] = os.path.join(os.environ["STATIC_DIRECTORY"], 'templates')
  67. globals.config = config