|
@@ -32,16 +32,8 @@ from urllib.parse import unquote, urlencode, urlparse
|
|
|
|
|
|
import markdown as md_lib
|
|
|
import tzlocal
|
|
|
-from flask import (
|
|
|
- Blueprint,
|
|
|
- Flask,
|
|
|
- g,
|
|
|
- has_app_context,
|
|
|
- jsonify,
|
|
|
- request,
|
|
|
- send_file,
|
|
|
- send_from_directory,
|
|
|
-)
|
|
|
+from fastapi import FastAPI
|
|
|
+from flask import Blueprint, Flask
|
|
|
from werkzeug.utils import secure_filename
|
|
|
|
|
|
import __main__ # noqa: F401
|
|
@@ -71,7 +63,18 @@ from .data.data_scope import _DataScopes
|
|
|
from .extension.library import Element, ElementLibrary
|
|
|
from .page import Page
|
|
|
from .partial import Partial
|
|
|
-from .server import _Server
|
|
|
+from .servers import (
|
|
|
+ ServerFrameworks,
|
|
|
+ _Server,
|
|
|
+ create_server,
|
|
|
+ get_request,
|
|
|
+ get_request_meta,
|
|
|
+ get_server_type,
|
|
|
+ has_server_context,
|
|
|
+ send_file,
|
|
|
+ send_from_directory,
|
|
|
+ set_server_type,
|
|
|
+)
|
|
|
from .state import State, _AsyncState, _GuiState
|
|
|
from .types import _WsType
|
|
|
from .utils import (
|
|
@@ -185,8 +188,8 @@ class Gui:
|
|
|
path_mapping: t.Optional[dict] = None,
|
|
|
env_filename: t.Optional[str] = None,
|
|
|
libraries: t.Optional[t.List[ElementLibrary]] = None,
|
|
|
- flask: t.Optional[Flask] = None,
|
|
|
script_paths: t.Union[str, Path, t.List[t.Union[str, Path]], None] = None,
|
|
|
+ server: t.Union[ServerFrameworks, Flask, FastAPI] = "flask",
|
|
|
):
|
|
|
"""Initialize a new Gui instance.
|
|
|
|
|
@@ -227,13 +230,11 @@ class Gui:
|
|
|
instances that pages can reference.<br/>
|
|
|
Using this argument is equivalent to calling `(Gui.)add_library()^` for each
|
|
|
list's elements.
|
|
|
- flask (Optional[Flask]): An optional instance of a Flask application object.<br/>
|
|
|
- If this argument is set, this `Gui` instance will use the value of this argument
|
|
|
- as the underlying server. If omitted or set to None, this `Gui` will create its
|
|
|
- own Flask application instance and use it to serve the pages.
|
|
|
script_paths (Union[str, Path, List[Union[str, Path]], None]):
|
|
|
Specifies the path(s) to the JavaScript files or external resources used by the application.
|
|
|
It can be a single URL or path, or a list containing multiple URLs and/or paths.
|
|
|
+ server (Union[ServerFrameworks, Flask, FastAPI]): The server type to use for the application.<br/>
|
|
|
+ The default value is `flask`.<br/>
|
|
|
"""
|
|
|
# store suspected local containing frame
|
|
|
self.__frame = t.cast(FrameType, t.cast(FrameType, currentframe()).f_back)
|
|
@@ -248,7 +249,21 @@ class Gui:
|
|
|
if path_mapping is None:
|
|
|
path_mapping = {}
|
|
|
self._path_mapping = path_mapping
|
|
|
- self._flask = flask
|
|
|
+
|
|
|
+ # Server config
|
|
|
+ self._server_instance: t.Union[Flask, FastAPI, None] = None
|
|
|
+ if isinstance(server, Flask):
|
|
|
+ set_server_type("flask")
|
|
|
+ self._server_instance = server
|
|
|
+ elif isinstance(server, FastAPI):
|
|
|
+ set_server_type("fastapi")
|
|
|
+ self._server_instance = server
|
|
|
+ elif isinstance(server, str) and server in t.get_args(ServerFrameworks):
|
|
|
+ set_server_type(server) # type: ignore[arg-type]
|
|
|
+ else:
|
|
|
+ raise ValueError(
|
|
|
+ f"Invalid 'server' option. 'server' must be one of {t.get_args(ServerFrameworks)} or a Flask or FastAPI instance." # noqa: E501
|
|
|
+ )
|
|
|
|
|
|
self._config = _Config()
|
|
|
self.__content_accessor = None
|
|
@@ -374,7 +389,6 @@ class Gui:
|
|
|
self.__client_id_2_sid: t.Dict[str, t.Set[str]] = {}
|
|
|
|
|
|
# Load default config
|
|
|
- self._flask_blueprint: t.List[Blueprint] = []
|
|
|
self._config._load(default_config)
|
|
|
|
|
|
# get taipy version
|
|
@@ -625,35 +639,35 @@ class Gui:
|
|
|
return (
|
|
|
_DataScopes._GLOBAL_ID
|
|
|
if self._bindings()._is_single_client()
|
|
|
- else getattr(g, Gui.__ARG_CLIENT_ID, "unknown id")
|
|
|
+ else getattr(get_request_meta(), Gui.__ARG_CLIENT_ID, "unknown id")
|
|
|
)
|
|
|
|
|
|
def __set_client_id_in_context(self, client_id: t.Optional[str] = None, force=False):
|
|
|
- if not client_id and request:
|
|
|
- client_id = request.args.get(Gui.__ARG_CLIENT_ID, "")
|
|
|
- if not client_id and (ws_client_id := getattr(g, "ws_client_id", None)):
|
|
|
+ if not client_id and get_request():
|
|
|
+ client_id = get_request().args.get(Gui.__ARG_CLIENT_ID, "")
|
|
|
+ if not client_id and (ws_client_id := getattr(get_request_meta(), "ws_client_id", None)):
|
|
|
client_id = ws_client_id
|
|
|
if not client_id and force:
|
|
|
res = self._bindings()._get_or_create_scope("")
|
|
|
client_id = res[0] if res[1] else None
|
|
|
- if client_id and request:
|
|
|
- if sid := getattr(request, "sid", None):
|
|
|
+ if client_id and get_request():
|
|
|
+ if sid := getattr(get_request(), "sid", None):
|
|
|
sids = self.__client_id_2_sid.get(client_id, None)
|
|
|
if sids is None:
|
|
|
sids = set()
|
|
|
self.__client_id_2_sid[client_id] = sids
|
|
|
sids.add(sid)
|
|
|
- g.client_id = client_id
|
|
|
+ get_request_meta().client_id = client_id
|
|
|
|
|
|
def __is_var_modified_in_context(self, var_name: str, derived_vars: t.Set[str]) -> bool:
|
|
|
- modified_vars: t.Optional[t.Set[str]] = getattr(g, "modified_vars", None)
|
|
|
- der_vars: t.Optional[t.Set[str]] = getattr(g, "derived_vars", None)
|
|
|
- setattr(g, "update_count", getattr(g, "update_count", 0) + 1) # noqa: B010
|
|
|
+ modified_vars: t.Optional[t.Set[str]] = getattr(get_request_meta(), "modified_vars", None)
|
|
|
+ der_vars: t.Optional[t.Set[str]] = getattr(get_request_meta(), "derived_vars", None)
|
|
|
+ setattr(get_request_meta(), "update_count", getattr(get_request_meta(), "update_count", 0) + 1) # noqa: B010
|
|
|
if modified_vars is None:
|
|
|
modified_vars = set()
|
|
|
- g.modified_vars = modified_vars
|
|
|
+ get_request_meta().modified_vars = modified_vars
|
|
|
if der_vars is None:
|
|
|
- g.derived_vars = derived_vars
|
|
|
+ get_request_meta().derived_vars = derived_vars
|
|
|
else:
|
|
|
der_vars.update(derived_vars)
|
|
|
if var_name in modified_vars:
|
|
@@ -662,15 +676,15 @@ class Gui:
|
|
|
return False
|
|
|
|
|
|
def __clean_vars_on_exit(self) -> t.Optional[t.Set[str]]:
|
|
|
- update_count = getattr(g, "update_count", 0) - 1
|
|
|
+ update_count = getattr(get_request_meta(), "update_count", 0) - 1
|
|
|
if update_count < 1:
|
|
|
- derived_vars: t.Set[str] = getattr(g, "derived_vars", set())
|
|
|
- delattr(g, "update_count")
|
|
|
- delattr(g, "modified_vars")
|
|
|
- delattr(g, "derived_vars")
|
|
|
+ derived_vars: t.Set[str] = getattr(get_request_meta(), "derived_vars", set())
|
|
|
+ delattr(get_request_meta(), "update_count")
|
|
|
+ delattr(get_request_meta(), "modified_vars")
|
|
|
+ delattr(get_request_meta(), "derived_vars")
|
|
|
return derived_vars
|
|
|
else:
|
|
|
- setattr(g, "update_count", update_count) # noqa: B010
|
|
|
+ setattr(get_request_meta(), "update_count", update_count) # noqa: B010
|
|
|
return None
|
|
|
|
|
|
def _handle_connect(self):
|
|
@@ -678,7 +692,9 @@ class Gui:
|
|
|
|
|
|
def _handle_disconnect(self):
|
|
|
_Hooks()._handle_disconnect(self)
|
|
|
- if (sid := getattr(request, "sid", None)) and (st_to := self._get_config("state_retention_period", 0)) > 0:
|
|
|
+ if (sid := getattr(get_request(), "sid", None)) and (
|
|
|
+ st_to := self._get_config("state_retention_period", 0)
|
|
|
+ ) > 0:
|
|
|
for cl_id, sids in self.__client_id_2_sid.items():
|
|
|
if sid in sids:
|
|
|
if len(sids) == 1:
|
|
@@ -695,7 +711,7 @@ class Gui:
|
|
|
except Exception as e:
|
|
|
_warn(f"Unexpected error removing state {client_id}", e)
|
|
|
|
|
|
- def _manage_message(self, msg_type: _WsType, message: dict) -> None:
|
|
|
+ def _manage_ws_message(self, msg_type: _WsType, message: dict) -> None:
|
|
|
try:
|
|
|
client_id = None
|
|
|
if msg_type == _WsType.CLIENT_ID.value:
|
|
@@ -710,7 +726,7 @@ class Gui:
|
|
|
self.__handle_ws_app_id({"name": message.get("name"), "payload": front_app_id})
|
|
|
expected_client_id = client_id or message.get(Gui.__ARG_CLIENT_ID)
|
|
|
self.__set_client_id_in_context(expected_client_id)
|
|
|
- g.ws_client_id = expected_client_id
|
|
|
+ get_request_meta().ws_client_id = expected_client_id
|
|
|
with self._set_locals_context(message.get("module_context") or None):
|
|
|
with self._get_authorization():
|
|
|
payload = message.get("payload", {})
|
|
@@ -903,7 +919,7 @@ class Gui:
|
|
|
if len(parts) > 1:
|
|
|
file_name = parts[-1]
|
|
|
(dir_path, as_attachment) = self.__get_content_accessor().get_content_path(
|
|
|
- path[: -len(file_name) - 1], file_name, request.args.get("bypass")
|
|
|
+ path[: -len(file_name) - 1], file_name, get_request().args.get("bypass")
|
|
|
)
|
|
|
if dir_path:
|
|
|
return send_from_directory(str(dir_path), file_name, as_attachment=as_attachment)
|
|
@@ -919,7 +935,7 @@ class Gui:
|
|
|
def __serve_user_content(self, path: str) -> t.Any:
|
|
|
self.__set_client_id_in_context()
|
|
|
q_args: t.Dict[str, str] = {}
|
|
|
- q_args.update(request.args)
|
|
|
+ q_args.update(get_request().args)
|
|
|
q_args.pop(Gui.__ARG_CLIENT_ID, None)
|
|
|
cb_function: t.Union[t.Callable, str, None] = None
|
|
|
cb_function_name = None
|
|
@@ -1028,17 +1044,17 @@ class Gui:
|
|
|
|
|
|
def __upload_files(self):
|
|
|
self.__set_client_id_in_context()
|
|
|
- on_upload_action = request.form.get("on_action", None)
|
|
|
- var_name = t.cast(str, request.form.get("var_name", None))
|
|
|
+ on_upload_action = get_request().form.get("on_action", None)
|
|
|
+ var_name = t.cast(str, get_request().form.get("var_name", None))
|
|
|
if not var_name and not on_upload_action:
|
|
|
_warn("upload files: No var name")
|
|
|
return ("upload files: No var name", 400)
|
|
|
- context = request.form.get("context", None)
|
|
|
- upload_data = request.form.get("upload_data", None)
|
|
|
- multiple = "multiple" in request.form and request.form["multiple"] == "True"
|
|
|
+ context = get_request().form.get("context", None)
|
|
|
+ upload_data = get_request().form.get("upload_data", None)
|
|
|
+ multiple = "multiple" in get_request().form and get_request().form["multiple"] == "True"
|
|
|
|
|
|
# File parsing and checks
|
|
|
- file = request.files.get("blob", None)
|
|
|
+ file = get_request().files.get("blob", None)
|
|
|
if not file:
|
|
|
_warn("upload files: No file part")
|
|
|
return ("upload files: No file part", 400)
|
|
@@ -1049,15 +1065,15 @@ class Gui:
|
|
|
return ("upload files: No selected file", 400)
|
|
|
|
|
|
# Path parsing and checks
|
|
|
- path = request.form.get("path", "")
|
|
|
+ path = get_request().form.get("path", "")
|
|
|
suffix = ""
|
|
|
complete = True
|
|
|
part = 0
|
|
|
|
|
|
- if "total" in request.form:
|
|
|
- total = int(request.form["total"])
|
|
|
- if total > 1 and "part" in request.form:
|
|
|
- part = int(request.form["part"])
|
|
|
+ if "total" in get_request().form:
|
|
|
+ total = int(get_request().form["total"])
|
|
|
+ if total > 1 and "part" in get_request().form:
|
|
|
+ part = int(get_request().form["part"])
|
|
|
suffix = f".part.{part}"
|
|
|
complete = part == total - 1
|
|
|
|
|
@@ -1405,8 +1421,7 @@ class Gui:
|
|
|
grouping_message = self.__get_message_grouping() if allow_grouping else None
|
|
|
if grouping_message is None:
|
|
|
try:
|
|
|
- self._server._ws.emit(
|
|
|
- "message",
|
|
|
+ self._server.send_ws_message(
|
|
|
payload,
|
|
|
to=t.cast(str, self.__get_ws_receiver(send_back_only)),
|
|
|
)
|
|
@@ -1419,7 +1434,7 @@ class Gui:
|
|
|
def __broadcast_ws(self, payload: dict, client_id: t.Optional[str] = None):
|
|
|
try:
|
|
|
to = list(self.__get_sids(client_id)) if client_id else []
|
|
|
- self._server._ws.emit("message", payload, to=t.cast(str, to) if to else None, include_self=True)
|
|
|
+ self._server.send_ws_message(payload, to=t.cast(str, to) if to else None, include_self=True)
|
|
|
time.sleep(0.001)
|
|
|
except Exception as e: # pragma: no cover
|
|
|
_warn(f"Exception raised in WebSocket communication in '{self.__frame.f_code.co_name}'", e)
|
|
@@ -1427,8 +1442,7 @@ class Gui:
|
|
|
def __send_ack(self, ack_id: t.Optional[str]) -> None:
|
|
|
if ack_id:
|
|
|
try:
|
|
|
- self._server._ws.emit(
|
|
|
- "message",
|
|
|
+ self._server.send_ws_message(
|
|
|
{"type": _WsType.ACKNOWLEDGEMENT.value, "id": ack_id},
|
|
|
to=t.cast(str, self.__get_ws_receiver(True)),
|
|
|
)
|
|
@@ -1539,7 +1553,7 @@ class Gui:
|
|
|
def __get_ws_receiver(self, send_back_only=False) -> t.Union[t.List[str], t.Any, None]:
|
|
|
if self._bindings()._is_single_client():
|
|
|
return None
|
|
|
- sid = getattr(request, "sid", None) if request else None
|
|
|
+ sid = getattr(get_request(), "sid", None) if get_request() else None
|
|
|
sids = self.__get_sids(self._get_client_id())
|
|
|
if sid:
|
|
|
sids.add(sid)
|
|
@@ -1705,13 +1719,13 @@ class Gui:
|
|
|
module_context (Optional[str]): The name of the module that will be used.
|
|
|
""" # noqa: E501
|
|
|
this_sid = None
|
|
|
- if request:
|
|
|
+ if get_request():
|
|
|
# avoid messing with the client_id => Set(ws id)
|
|
|
- this_sid = getattr(request, "sid", None)
|
|
|
- request.sid = None # type: ignore[attr-defined]
|
|
|
+ this_sid = getattr(get_request(), "sid", None)
|
|
|
+ get_request().sid = None # type: ignore[attr-defined]
|
|
|
try:
|
|
|
- with self.get_flask_app().app_context():
|
|
|
- setattr(g, Gui.__ARG_CLIENT_ID, state_id)
|
|
|
+ with self.get_server_instance().app_context():
|
|
|
+ setattr(get_request_meta(), Gui.__ARG_CLIENT_ID, state_id)
|
|
|
with self._set_module_context(module_context):
|
|
|
if not _is_function(callback):
|
|
|
callback = self._get_user_function(t.cast(str, callback))
|
|
@@ -1727,7 +1741,7 @@ class Gui:
|
|
|
)
|
|
|
finally:
|
|
|
if this_sid:
|
|
|
- request.sid = this_sid # type: ignore[attr-defined]
|
|
|
+ get_request().sid = this_sid # type: ignore[attr-defined]
|
|
|
return None
|
|
|
|
|
|
def broadcast_callback(
|
|
@@ -1798,7 +1812,7 @@ class Gui:
|
|
|
|
|
|
def _is_in_brdcst_callback(self):
|
|
|
try:
|
|
|
- return getattr(g, Gui.__BRDCST_CALLBACK_G_ID, False)
|
|
|
+ return getattr(get_request_meta(), Gui.__BRDCST_CALLBACK_G_ID, False)
|
|
|
except RuntimeError:
|
|
|
return False
|
|
|
|
|
@@ -2069,8 +2083,14 @@ class Gui:
|
|
|
def _get_root_page_name():
|
|
|
return Gui.__root_page_name
|
|
|
|
|
|
+ # Deprecated
|
|
|
def _set_flask(self, flask: Flask):
|
|
|
- self._flask = flask
|
|
|
+ raise RuntimeError(
|
|
|
+ "'_set_flask()' is deprecated. Use '_set_web_server()' instead as multiple web frameworks has been supported." # noqa: E501
|
|
|
+ )
|
|
|
+
|
|
|
+ def _set_web_server(self, server: t.Union[Flask, FastAPI]):
|
|
|
+ self._server_instance = server
|
|
|
|
|
|
def _get_default_module_name(self):
|
|
|
return self.__default_module_name
|
|
@@ -2378,11 +2398,11 @@ class Gui:
|
|
|
|
|
|
def _set_broadcast(self, broadcast: bool = True):
|
|
|
with contextlib.suppress(RuntimeError):
|
|
|
- setattr(g, Gui.__BROADCAST_G_ID, broadcast)
|
|
|
+ setattr(get_request_meta(), Gui.__BROADCAST_G_ID, broadcast)
|
|
|
|
|
|
def _is_broadcasting(self) -> bool:
|
|
|
try:
|
|
|
- return getattr(g, Gui.__BROADCAST_G_ID, False)
|
|
|
+ return getattr(get_request_meta(), Gui.__BROADCAST_G_ID, False)
|
|
|
except RuntimeError:
|
|
|
return False
|
|
|
|
|
@@ -2549,7 +2569,7 @@ class Gui:
|
|
|
nav_page = page_name
|
|
|
if hasattr(self, "on_navigate") and _is_function(self.on_navigate):
|
|
|
try:
|
|
|
- params = request.args.to_dict() if hasattr(request, "args") else {}
|
|
|
+ params = get_request().args.to_dict() if hasattr(get_request(), "args") else {}
|
|
|
params.pop("client_id", None)
|
|
|
params.pop("v", None)
|
|
|
nav_page = self._call_function_with_state(
|
|
@@ -2589,7 +2609,7 @@ class Gui:
|
|
|
"""Handle the bindings of custom page variables"""
|
|
|
if not isinstance(page, CustomPage):
|
|
|
return
|
|
|
- with self.get_flask_app().app_context() if has_app_context() else contextlib.nullcontext(): # type: ignore[attr-defined]
|
|
|
+ with self.get_server_instance().app_context() if has_server_context() else contextlib.nullcontext(): # type: ignore[attr-defined]
|
|
|
self.__set_client_id_in_context(client_id)
|
|
|
with self._set_locals_context(page._get_module_name()):
|
|
|
for k, v in self._get_locals_bind().items():
|
|
@@ -2612,7 +2632,7 @@ class Gui:
|
|
|
# Make sure that there is a page instance found
|
|
|
if page is None:
|
|
|
return (
|
|
|
- jsonify({"error": f"Page '{nav_page}' doesn't exist."}),
|
|
|
+ self._server.direct_render_json({"error": f"Page '{nav_page}' doesn't exist."}),
|
|
|
400,
|
|
|
{"Content-Type": "application/json; charset=utf-8"},
|
|
|
)
|
|
@@ -2640,7 +2660,7 @@ class Gui:
|
|
|
if page._rendered_jsx is not None:
|
|
|
with self._set_locals_context(context):
|
|
|
self._call_on_page_load(nav_page)
|
|
|
- return self._server._render(
|
|
|
+ return self._server.render(
|
|
|
page._rendered_jsx,
|
|
|
page._script_paths if page._script_paths is not None else [],
|
|
|
page._style if page._style is not None else "",
|
|
@@ -2651,7 +2671,7 @@ class Gui:
|
|
|
return ("No page template", 404)
|
|
|
|
|
|
def _render_route(self) -> t.Any:
|
|
|
- return self._server._direct_render_json(
|
|
|
+ return self._server.direct_render_json(
|
|
|
{
|
|
|
"locations": {
|
|
|
"/" if route == Gui.__root_page_name else f"/{route}": f"/{route}" for route in self._config.routes
|
|
@@ -2660,17 +2680,20 @@ class Gui:
|
|
|
}
|
|
|
)
|
|
|
|
|
|
- def get_flask_app(self) -> Flask:
|
|
|
- """Get the internal Flask application.
|
|
|
+ def get_flask_app(self):
|
|
|
+ raise RuntimeError("'get_flask_app()' is deprecated. Use 'get_server_instance()' instead.")
|
|
|
+
|
|
|
+ def get_server_instance(self) -> t.Union[Flask, FastAPI]:
|
|
|
+ """Get the internal server application.
|
|
|
|
|
|
This method must be called **after** `(Gui.)run()^` was invoked.
|
|
|
|
|
|
Returns:
|
|
|
- The Flask instance used.
|
|
|
+ The server instance used.
|
|
|
"""
|
|
|
if hasattr(self, "_server"):
|
|
|
- return t.cast(Flask, self._server.get_flask())
|
|
|
- raise RuntimeError("get_flask_app() cannot be invoked before run() has been called.")
|
|
|
+ return t.cast(Flask, self._server.get_server_instance())
|
|
|
+ raise RuntimeError("get_server_instance() cannot be invoked before run() has been called.")
|
|
|
|
|
|
def _get_port(self) -> int:
|
|
|
return self._server.get_port()
|
|
@@ -2745,10 +2768,10 @@ class Gui:
|
|
|
app_config = self._config.config
|
|
|
# Init server if there is no server
|
|
|
if not hasattr(self, "_server"):
|
|
|
- self._server = _Server(
|
|
|
+ self._server = create_server(
|
|
|
self, # type: ignore[arg-type]
|
|
|
path_mapping=self._path_mapping,
|
|
|
- flask=self._flask,
|
|
|
+ flask=self._server_instance,
|
|
|
async_mode=app_config.get("async_mode"),
|
|
|
allow_upgrades=not app_config.get("notebook_proxy"),
|
|
|
server_config=app_config.get("server_config"),
|
|
@@ -2757,11 +2780,10 @@ class Gui:
|
|
|
# Stop and reinitialize the server if it is still running as a thread
|
|
|
if (_is_in_notebook() or app_config.get("run_in_thread")) and hasattr(self._server, "_thread"):
|
|
|
self.stop()
|
|
|
- self._flask_blueprint = []
|
|
|
- self._server = _Server(
|
|
|
+ self._server = create_server(
|
|
|
self, # type: ignore[arg-type]
|
|
|
path_mapping=self._path_mapping,
|
|
|
- flask=self._flask,
|
|
|
+ flask=self._server_instance,
|
|
|
async_mode=app_config.get("async_mode"),
|
|
|
allow_upgrades=not app_config.get("notebook_proxy"),
|
|
|
server_config=app_config.get("server_config"),
|
|
@@ -2785,7 +2807,7 @@ class Gui:
|
|
|
_TaipyLogger._get_logger().info(f" * NGROK Public Url: {self._ngrok[0].public_url}")
|
|
|
|
|
|
def __bind_default_function(self):
|
|
|
- with self.get_flask_app().app_context():
|
|
|
+ with self.get_server_instance().app_context():
|
|
|
if additional_pages := _Hooks()._get_additional_pages():
|
|
|
# add page context for additional pages so that they can be managed by the variable directory
|
|
|
for page in additional_pages:
|
|
@@ -2803,6 +2825,14 @@ class Gui:
|
|
|
self.__bind_local_func("on_user_content")
|
|
|
|
|
|
def __register_blueprint(self):
|
|
|
+ server_type = get_server_type()
|
|
|
+ if server_type == "flask":
|
|
|
+ self.__register_flask_blueprint()
|
|
|
+ if server_type == "fastapi":
|
|
|
+ self.__register_fastapi_blueprint()
|
|
|
+
|
|
|
+ def __register_flask_blueprint(self):
|
|
|
+ flask_blueprint: t.List[Blueprint] = []
|
|
|
# add en empty main page if it is not defined
|
|
|
if Gui.__root_page_name not in self._config.routes:
|
|
|
new_page = _Page()
|
|
@@ -2812,22 +2842,22 @@ class Gui:
|
|
|
self._config.routes.append(Gui.__root_page_name)
|
|
|
|
|
|
pages_bp = Blueprint("taipy_pages", __name__)
|
|
|
- self._flask_blueprint.append(pages_bp)
|
|
|
+ flask_blueprint.append(pages_bp)
|
|
|
|
|
|
# server URL Rule for taipy images
|
|
|
images_bp = Blueprint("taipy_images", __name__)
|
|
|
images_bp.add_url_rule(f"/{Gui.__CONTENT_ROOT}/<path:path>", view_func=self.__serve_content)
|
|
|
- self._flask_blueprint.append(images_bp)
|
|
|
+ flask_blueprint.append(images_bp)
|
|
|
|
|
|
# server URL for uploaded files
|
|
|
upload_bp = Blueprint("taipy_upload", __name__)
|
|
|
upload_bp.add_url_rule(f"/{Gui.__UPLOAD_URL}", view_func=self.__upload_files, methods=["POST"])
|
|
|
- self._flask_blueprint.append(upload_bp)
|
|
|
+ flask_blueprint.append(upload_bp)
|
|
|
|
|
|
# server URL for user content
|
|
|
user_content_bp = Blueprint("taipy_user_content", __name__)
|
|
|
user_content_bp.add_url_rule(f"/{Gui.__USER_CONTENT_URL}/<path:path>", view_func=self.__serve_user_content)
|
|
|
- self._flask_blueprint.append(user_content_bp)
|
|
|
+ flask_blueprint.append(user_content_bp)
|
|
|
|
|
|
# server URL for extension resources
|
|
|
extension_bp = Blueprint("taipy_extensions", __name__)
|
|
@@ -2854,11 +2884,11 @@ class Gui:
|
|
|
if self.__script_files:
|
|
|
scripts.extend(self.__script_files)
|
|
|
|
|
|
- self._flask_blueprint.append(extension_bp)
|
|
|
+ flask_blueprint.append(extension_bp)
|
|
|
|
|
|
_webapp_path = self._get_webapp_path()
|
|
|
|
|
|
- self._flask_blueprint.append(
|
|
|
+ flask_blueprint.append(
|
|
|
self._server._get_default_blueprint(
|
|
|
static_folder=_webapp_path,
|
|
|
template_folder=_webapp_path,
|
|
@@ -2884,8 +2914,11 @@ class Gui:
|
|
|
_Hooks()._add_external_blueprint(self, __name__)
|
|
|
|
|
|
# Register Flask Blueprint if available
|
|
|
- for bp in self._flask_blueprint:
|
|
|
- t.cast(Flask, self._server.get_flask()).register_blueprint(bp)
|
|
|
+ for bp in flask_blueprint:
|
|
|
+ t.cast(Flask, self._server.get_server_instance()).register_blueprint(bp)
|
|
|
+
|
|
|
+ def __register_fastapi_blueprint(self):
|
|
|
+ pass
|
|
|
|
|
|
def _get_accessor(self):
|
|
|
if self.__accessors is None:
|
|
@@ -2898,7 +2931,7 @@ class Gui:
|
|
|
run_in_thread: bool = False,
|
|
|
async_mode: str = "gevent",
|
|
|
**kwargs,
|
|
|
- ) -> t.Optional[Flask]:
|
|
|
+ ) -> t.Union[Flask, FastAPI, None]:
|
|
|
"""Start the server that delivers pages to web clients.
|
|
|
|
|
|
Once you enter `run()`, users can run web browsers and point to the web server
|
|
@@ -3052,7 +3085,7 @@ class Gui:
|
|
|
|
|
|
# Start Flask Server
|
|
|
if not run_server:
|
|
|
- return self.get_flask_app()
|
|
|
+ return self.get_server_instance()
|
|
|
|
|
|
return self._server.run(
|
|
|
host=app_config.get("host"),
|
|
@@ -3060,7 +3093,7 @@ class Gui:
|
|
|
client_url=app_config.get("client_url"),
|
|
|
debug=app_config.get("debug"),
|
|
|
use_reloader=app_config.get("use_reloader"),
|
|
|
- flask_log=app_config.get("flask_log"),
|
|
|
+ server_log=app_config.get("server_log"),
|
|
|
run_in_thread=app_config.get("run_in_thread"),
|
|
|
allow_unsafe_werkzeug=app_config.get("allow_unsafe_werkzeug"),
|
|
|
notebook_proxy=app_config.get("notebook_proxy"),
|
|
@@ -3147,16 +3180,16 @@ class Gui:
|
|
|
self, event_name: str, client_id: t.Optional[str] = None, payload: t.Optional[t.Dict[str, t.Any]] = None
|
|
|
):
|
|
|
this_sid = None
|
|
|
- if request:
|
|
|
+ if get_request():
|
|
|
# avoid messing with the client_id => Set(ws id)
|
|
|
- this_sid = getattr(request, "sid", None)
|
|
|
- request.sid = None # type: ignore[attr-defined]
|
|
|
+ this_sid = getattr(get_request(), "sid", None)
|
|
|
+ get_request().sid = None # type: ignore[attr-defined]
|
|
|
|
|
|
try:
|
|
|
- with self.get_flask_app().app_context(), self.__event_manager:
|
|
|
+ with self.get_server_instance().app_context(), self.__event_manager:
|
|
|
if client_id:
|
|
|
- setattr(g, Gui.__ARG_CLIENT_ID, client_id)
|
|
|
+ setattr(get_request_meta(), Gui.__ARG_CLIENT_ID, client_id)
|
|
|
_Hooks()._fire_event(event_name, client_id, payload)
|
|
|
finally:
|
|
|
if this_sid:
|
|
|
- request.sid = this_sid # type: ignore[attr-defined]
|
|
|
+ get_request().sid = this_sid # type: ignore[attr-defined]
|