routes.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. import inspect
  2. import os.path
  3. from functools import wraps
  4. from typing import List
  5. import justpy as jp
  6. from starlette.requests import Request
  7. from starlette.responses import FileResponse, PlainTextResponse
  8. from starlette.routing import BaseRoute, Mount, Route, compile_path
  9. from starlette.staticfiles import StaticFiles
  10. from . import globals
  11. from .helpers import is_coroutine
  12. def add_route(self, route: BaseRoute) -> None:
  13. """
  14. :param route: starlette route including a path and a function to be called
  15. :return:
  16. """
  17. globals.app.routes.insert(0, route)
  18. def add_static_files(self, path: str, directory: str) -> None:
  19. """
  20. :param path: string that starts with a '/'
  21. :param directory: folder with static files to serve under the given path
  22. """
  23. add_route(None, Mount(path, app=StaticFiles(directory=directory)))
  24. def get(self, path: str):
  25. """
  26. Use as a decorator for a function like @ui.get('/another/route/{id}').
  27. :param path: string that starts with a '/'
  28. :return:
  29. """
  30. *_, converters = compile_path(path)
  31. def decorator(func):
  32. @wraps(func)
  33. async def decorated(request: Request):
  34. args = {name: converter.convert(request.path_params.get(name)) for name, converter in converters.items()}
  35. parameters = inspect.signature(func).parameters
  36. for key in parameters:
  37. if parameters[key].annotation.__name__ == 'bool':
  38. args[key] = bool(args[key])
  39. if parameters[key].annotation.__name__ == 'int':
  40. args[key] = int(args[key])
  41. elif parameters[key].annotation.__name__ == 'float':
  42. args[key] = float(args[key])
  43. elif parameters[key].annotation.__name__ == 'complex':
  44. args[key] = complex(args[key])
  45. if 'request' in parameters and 'request' not in args:
  46. args['request'] = request
  47. return await func(**args) if is_coroutine(func) else func(**args)
  48. self.add_route(Route(path, decorated))
  49. return decorated
  50. return decorator
  51. def add_dependencies(py_filepath: str, dependencies: List[str] = []) -> None:
  52. vue_filepath = os.path.splitext(os.path.realpath(py_filepath))[0] + '.js'
  53. for dependency in dependencies:
  54. is_remote = dependency.startswith('http://') or dependency.startswith('https://')
  55. src = dependency if is_remote else f'lib/{dependency}'
  56. if src not in jp.component_file_list:
  57. jp.component_file_list += [src]
  58. if not is_remote:
  59. filepath = f'{os.path.dirname(vue_filepath)}/{src}'
  60. route = Route(f'/{src}', lambda _, filepath=filepath: FileResponse(filepath))
  61. jp.app.routes.insert(0, route)
  62. if vue_filepath not in jp.component_file_list:
  63. filename = os.path.basename(vue_filepath)
  64. jp.app.routes.insert(0, Route(f'/{filename}', lambda _: FileResponse(vue_filepath)))
  65. jp.component_file_list += [filename]
  66. def create_exclude_routes() -> None:
  67. def void(_: Request) -> PlainTextResponse:
  68. return PlainTextResponse()
  69. if 'chart' in globals.config.excludes:
  70. add_route(None, Route('/templates/local/highcharts.js', void))
  71. if 'colors' in globals.config.excludes:
  72. add_route(None, Route('/colors.js', void))
  73. if 'custom_example' in globals.config.excludes:
  74. add_route(None, Route('/custom_example.js', void))
  75. if 'interactive_image' in globals.config.excludes:
  76. add_route(None, Route('/interactive_image.js', void))
  77. if 'keyboard' in globals.config.excludes:
  78. add_route(None, Route('/keyboard.js', void))
  79. if 'log' in globals.config.excludes:
  80. add_route(None, Route('/log.js', void))
  81. if 'joystick' in globals.config.excludes:
  82. add_route(None, Route('/joystick.js', void))
  83. add_route(None, Route('/lib/nipplejs.min.js', void))
  84. if 'scene' in globals.config.excludes:
  85. add_route(None, Route('/scene.js', void))
  86. add_route(None, Route('/lib/CSS2DRenderer.js', void))
  87. add_route(None, Route('/lib/CSS3DRenderer.js', void))
  88. add_route(None, Route('/lib/OrbitControls.js', void))
  89. add_route(None, Route('/lib/STLLoader.js', void))
  90. add_route(None, Route('/lib/three.min.js', void))
  91. add_route(None, Route('/lib/tween.umd.min.js', void))
  92. if 'table' in globals.config.excludes:
  93. add_route(None, Route('/templates/local/ag-grid-community.js', void))