flet-web 0.29.0.dev5039__py3-none-any.whl → 0.70.0.dev5066__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- flet_web/__init__.py +8 -1
- flet_web/fastapi/__init__.py +2 -0
- flet_web/fastapi/app.py +44 -17
- flet_web/fastapi/flet_app.py +195 -288
- flet_web/fastapi/flet_app_manager.py +41 -64
- flet_web/fastapi/flet_oauth.py +2 -1
- flet_web/fastapi/flet_static_files.py +54 -50
- flet_web/fastapi/serve_fastapi_web_app.py +30 -27
- flet_web/patch_index.py +35 -35
- flet_web/version.py +1 -1
- flet_web/web/assets/NOTICES +1815 -3803
- flet_web/web/assets/fonts/roboto.woff2 +0 -0
- flet_web/web/assets/packages/media_kit/assets/web/hls1.4.10.js +2 -2
- flet_web/web/canvaskit/canvaskit.js +192 -0
- flet_web/web/canvaskit/canvaskit.js.symbols +12098 -0
- flet_web/web/canvaskit/canvaskit.wasm +0 -0
- flet_web/web/canvaskit/chromium/canvaskit.js +192 -0
- flet_web/web/canvaskit/chromium/canvaskit.js.symbols +11050 -0
- flet_web/web/canvaskit/chromium/canvaskit.wasm +0 -0
- flet_web/web/canvaskit/skwasm.js +137 -0
- flet_web/web/canvaskit/skwasm.js.symbols +12073 -0
- flet_web/web/canvaskit/skwasm.wasm +0 -0
- flet_web/web/flutter.js +30 -2
- flet_web/web/flutter.js.map +3 -3
- flet_web/web/flutter_bootstrap.js +50 -10
- flet_web/web/flutter_service_worker.js +23 -21
- flet_web/web/index.html +56 -11
- flet_web/web/main.dart.js +170400 -167642
- flet_web/web/main.dart.mjs +44188 -0
- flet_web/web/main.dart.wasm +0 -0
- flet_web/web/pyodide/ffi.d.ts +10 -1
- flet_web/web/pyodide/micropip-0.8.0-py3-none-any.whl +14 -0
- flet_web/web/pyodide/package.json +2 -2
- flet_web/web/pyodide/packaging-24.2-py3-none-any.whl +0 -0
- flet_web/web/pyodide/pyodide-lock.json +1 -1
- flet_web/web/pyodide/pyodide.asm.js +1 -1
- flet_web/web/pyodide/pyodide.asm.wasm +0 -0
- flet_web/web/pyodide/pyodide.d.ts +15 -3
- flet_web/web/pyodide/pyodide.js +1 -1
- flet_web/web/pyodide/pyodide.mjs +2 -2
- flet_web/web/pyodide/python_stdlib.zip +0 -0
- flet_web/web/python-worker.js +75 -24
- flet_web/web/python.js +62 -20
- {flet_web-0.29.0.dev5039.dist-info → flet_web-0.70.0.dev5066.dist-info}/METADATA +3 -3
- flet_web-0.70.0.dev5066.dist-info/RECORD +71 -0
- flet_web-0.29.0.dev5039.dist-info/RECORD +0 -57
- {flet_web-0.29.0.dev5039.dist-info → flet_web-0.70.0.dev5066.dist-info}/WHEEL +0 -0
- {flet_web-0.29.0.dev5039.dist-info → flet_web-0.70.0.dev5066.dist-info}/top_level.txt +0 -0
|
@@ -1,17 +1,14 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import logging
|
|
3
3
|
import shutil
|
|
4
|
-
import threading
|
|
5
4
|
import traceback
|
|
6
5
|
from concurrent.futures import ThreadPoolExecutor
|
|
7
6
|
from datetime import datetime, timezone
|
|
8
7
|
from typing import Optional
|
|
9
8
|
|
|
10
|
-
from flet.
|
|
11
|
-
from flet.
|
|
12
|
-
from flet.
|
|
13
|
-
from flet.core.pubsub.pubsub_hub import PubSubHub
|
|
14
|
-
from flet.utils import is_pyodide
|
|
9
|
+
from flet.messaging.connection import Connection
|
|
10
|
+
from flet.messaging.session import Session
|
|
11
|
+
from flet.pubsub.pubsub_hub import PubSubHub
|
|
15
12
|
|
|
16
13
|
import flet_web.fastapi as flet_fastapi
|
|
17
14
|
from flet_web.fastapi.oauth_state import OAuthState
|
|
@@ -25,15 +22,12 @@ class FletAppManager:
|
|
|
25
22
|
"""
|
|
26
23
|
|
|
27
24
|
def __init__(self):
|
|
28
|
-
self.
|
|
29
|
-
self.__sessions: dict[str, Page] = {}
|
|
25
|
+
self.__sessions: dict[str, Session] = {}
|
|
30
26
|
self.__evict_sessions_task = None
|
|
31
27
|
self.__states: dict[str, OAuthState] = {}
|
|
32
|
-
self.__states_lock = threading.Lock() if not is_pyodide() else NopeLock()
|
|
33
28
|
self.__evict_oauth_states_task = None
|
|
34
29
|
self.__temp_dirs = {}
|
|
35
30
|
self.__executor = ThreadPoolExecutor(thread_name_prefix="flet_fastapi")
|
|
36
|
-
self.__pubsubhubs_lock = threading.Lock() if not is_pyodide() else NopeLock()
|
|
37
31
|
self.__pubsubhubs = {}
|
|
38
32
|
|
|
39
33
|
@property
|
|
@@ -43,19 +37,19 @@ class FletAppManager:
|
|
|
43
37
|
def get_pubsubhub(
|
|
44
38
|
self, session_handler, loop: Optional[asyncio.AbstractEventLoop] = None
|
|
45
39
|
):
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
return psh
|
|
40
|
+
psh = self.__pubsubhubs.get(session_handler, None)
|
|
41
|
+
if psh is None:
|
|
42
|
+
psh = PubSubHub(
|
|
43
|
+
loop=loop or asyncio.get_running_loop(),
|
|
44
|
+
executor=self.__executor,
|
|
45
|
+
)
|
|
46
|
+
self.__pubsubhubs[session_handler] = psh
|
|
47
|
+
return psh
|
|
55
48
|
|
|
56
49
|
async def start(self):
|
|
57
50
|
"""
|
|
58
|
-
Background task evicting expired app data. Must be called at FastAPI
|
|
51
|
+
Background task evicting expired app data. Must be called at FastAPI
|
|
52
|
+
application startup.
|
|
59
53
|
"""
|
|
60
54
|
if not self.__evict_sessions_task:
|
|
61
55
|
logger.info("Starting up Flet App Manager")
|
|
@@ -77,44 +71,31 @@ class FletAppManager:
|
|
|
77
71
|
if self.__evict_oauth_states_task:
|
|
78
72
|
self.__evict_oauth_states_task.cancel()
|
|
79
73
|
|
|
80
|
-
async def get_session(self, session_id: str) -> Optional[
|
|
81
|
-
|
|
82
|
-
return self.__sessions.get(session_id)
|
|
74
|
+
async def get_session(self, session_id: str) -> Optional[Session]:
|
|
75
|
+
return self.__sessions.get(session_id)
|
|
83
76
|
|
|
84
|
-
async def add_session(self, session_id: str,
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
logger.info(
|
|
88
|
-
f"New session created ({len(self.__sessions)} total): {session_id}"
|
|
89
|
-
)
|
|
77
|
+
async def add_session(self, session_id: str, session: Session):
|
|
78
|
+
self.__sessions[session_id] = session
|
|
79
|
+
logger.info(f"New session created ({len(self.__sessions)} total): {session_id}")
|
|
90
80
|
|
|
91
81
|
async def reconnect_session(self, session_id: str, conn: Connection):
|
|
92
82
|
logger.info(f"Session reconnected: {session_id}")
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
old_conn = page.connection
|
|
97
|
-
await page._connect(conn)
|
|
98
|
-
if old_conn:
|
|
99
|
-
old_conn.dispose()
|
|
83
|
+
if session_id in self.__sessions:
|
|
84
|
+
session = self.__sessions[session_id]
|
|
85
|
+
await session.connect(conn)
|
|
100
86
|
|
|
101
87
|
async def disconnect_session(self, session_id: str, session_timeout_seconds: int):
|
|
102
88
|
logger.info(f"Session disconnected: {session_id}")
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
await self.__sessions[session_id]._disconnect(session_timeout_seconds)
|
|
89
|
+
if session_id in self.__sessions:
|
|
90
|
+
await self.__sessions[session_id].disconnect(session_timeout_seconds)
|
|
106
91
|
|
|
107
92
|
async def delete_session(self, session_id: str):
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
if page is not None:
|
|
93
|
+
session = self.__sessions.pop(session_id, None)
|
|
94
|
+
total = len(self.__sessions)
|
|
95
|
+
if session is not None:
|
|
112
96
|
logger.info(f"Delete session ({total} left): {session_id}")
|
|
113
97
|
try:
|
|
114
|
-
|
|
115
|
-
page._close()
|
|
116
|
-
if old_conn:
|
|
117
|
-
old_conn.dispose()
|
|
98
|
+
session.close()
|
|
118
99
|
except Exception as e:
|
|
119
100
|
logger.error(
|
|
120
101
|
f"Error deleting expired session: {e} {traceback.format_exc()}"
|
|
@@ -122,12 +103,10 @@ class FletAppManager:
|
|
|
122
103
|
|
|
123
104
|
def store_state(self, state_id: str, state: OAuthState):
|
|
124
105
|
logger.info(f"Store oauth state: {state_id}")
|
|
125
|
-
|
|
126
|
-
self.__states[state_id] = state
|
|
106
|
+
self.__states[state_id] = state
|
|
127
107
|
|
|
128
108
|
def retrieve_state(self, state_id: str) -> Optional[OAuthState]:
|
|
129
|
-
|
|
130
|
-
return self.__states.pop(state_id, None)
|
|
109
|
+
return self.__states.pop(state_id, None)
|
|
131
110
|
|
|
132
111
|
def add_temp_dir(self, temp_dir: str):
|
|
133
112
|
self.__temp_dirs[temp_dir] = True
|
|
@@ -136,30 +115,28 @@ class FletAppManager:
|
|
|
136
115
|
while True:
|
|
137
116
|
await asyncio.sleep(10)
|
|
138
117
|
session_ids = []
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
118
|
+
for session_id, session in self.__sessions.items():
|
|
119
|
+
if (
|
|
120
|
+
session.expires_at
|
|
121
|
+
and datetime.now(timezone.utc) > session.expires_at
|
|
122
|
+
):
|
|
123
|
+
session_ids.append(session_id)
|
|
143
124
|
for session_id in session_ids:
|
|
144
125
|
await self.delete_session(session_id)
|
|
145
126
|
|
|
146
127
|
async def __evict_expired_oauth_states(self):
|
|
147
128
|
while True:
|
|
148
129
|
await asyncio.sleep(10)
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
state.expires_at
|
|
154
|
-
and datetime.now(timezone.utc) > state.expires_at
|
|
155
|
-
):
|
|
156
|
-
ids.append(id)
|
|
130
|
+
ids = []
|
|
131
|
+
for id, state in self.__states.items():
|
|
132
|
+
if state.expires_at and datetime.now(timezone.utc) > state.expires_at:
|
|
133
|
+
ids.append(id)
|
|
157
134
|
for id in ids:
|
|
158
135
|
logger.info(f"Delete expired oauth state: {id}")
|
|
159
136
|
self.retrieve_state(id)
|
|
160
137
|
|
|
161
138
|
def delete_temp_dirs(self):
|
|
162
|
-
for temp_dir in self.__temp_dirs
|
|
139
|
+
for temp_dir in self.__temp_dirs:
|
|
163
140
|
logger.info(f"Deleting temp dir: {temp_dir}")
|
|
164
141
|
shutil.rmtree(temp_dir, ignore_errors=True)
|
|
165
142
|
|
flet_web/fastapi/flet_oauth.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from fastapi import HTTPException, Request
|
|
2
2
|
from fastapi.responses import HTMLResponse, RedirectResponse
|
|
3
|
+
|
|
3
4
|
from flet_web.fastapi.flet_app_manager import app_manager
|
|
4
5
|
|
|
5
6
|
|
|
@@ -33,7 +34,7 @@ class FletOAuth:
|
|
|
33
34
|
if not session:
|
|
34
35
|
raise HTTPException(status_code=500, detail="Session not found")
|
|
35
36
|
|
|
36
|
-
await session._authorize_callback_async(
|
|
37
|
+
await session.page._authorize_callback_async(
|
|
37
38
|
{
|
|
38
39
|
"state": state_id,
|
|
39
40
|
"code": request.query_params.get("code"),
|
|
@@ -3,16 +3,22 @@ import os
|
|
|
3
3
|
import shutil
|
|
4
4
|
import tempfile
|
|
5
5
|
from pathlib import Path
|
|
6
|
-
from typing import Optional
|
|
6
|
+
from typing import Optional
|
|
7
7
|
|
|
8
|
-
import flet_web.fastapi as flet_fastapi
|
|
9
8
|
from fastapi.staticfiles import StaticFiles
|
|
10
|
-
from flet.
|
|
9
|
+
from flet.controls.types import RouteUrlStrategy, WebRenderer
|
|
11
10
|
from flet.utils import Once, get_bool_env_var
|
|
12
|
-
from flet_web import get_package_web_dir, patch_index_html, patch_manifest_json
|
|
13
|
-
from flet_web.fastapi.flet_app_manager import app_manager
|
|
14
11
|
from starlette.types import Receive, Scope, Send
|
|
15
12
|
|
|
13
|
+
import flet_web.fastapi as flet_fastapi
|
|
14
|
+
from flet_web import (
|
|
15
|
+
get_package_web_dir,
|
|
16
|
+
patch_font_manifest_json,
|
|
17
|
+
patch_index_html,
|
|
18
|
+
patch_manifest_json,
|
|
19
|
+
)
|
|
20
|
+
from flet_web.fastapi.flet_app_manager import app_manager
|
|
21
|
+
|
|
16
22
|
logger = logging.getLogger(flet_fastapi.__name__)
|
|
17
23
|
|
|
18
24
|
|
|
@@ -27,10 +33,11 @@ class FletStaticFiles(StaticFiles):
|
|
|
27
33
|
* `app_name` (str, optional) - PWA application name.
|
|
28
34
|
* `app_short_name` (str, optional) - PWA application short name.
|
|
29
35
|
* `app_description` (str, optional) - PWA application description.
|
|
30
|
-
* `web_renderer` (WebRenderer) - web renderer defaulting to `WebRenderer.
|
|
31
|
-
* `use_color_emoji` (bool) - whether to load a font with color emoji. Default is `False`.
|
|
36
|
+
* `web_renderer` (WebRenderer) - web renderer defaulting to `WebRenderer.AUTO`.
|
|
32
37
|
* `route_url_strategy` (str) - routing URL strategy: `path` (default) or `hash`.
|
|
33
|
-
* `
|
|
38
|
+
* `no_cdn` - do not load CanvasKit, Pyodide and fonts from CDN
|
|
39
|
+
* `websocket_endpoint_path` (str, optional) - absolute URL of Flet app
|
|
40
|
+
WebSocket handler. Default is `{app_mount_path}/ws`.
|
|
34
41
|
"""
|
|
35
42
|
|
|
36
43
|
def __init__(
|
|
@@ -40,21 +47,22 @@ class FletStaticFiles(StaticFiles):
|
|
|
40
47
|
app_name: Optional[str] = None,
|
|
41
48
|
app_short_name: Optional[str] = None,
|
|
42
49
|
app_description: Optional[str] = None,
|
|
43
|
-
web_renderer: WebRenderer = WebRenderer.
|
|
44
|
-
|
|
45
|
-
|
|
50
|
+
web_renderer: WebRenderer = WebRenderer.AUTO,
|
|
51
|
+
route_url_strategy: RouteUrlStrategy = RouteUrlStrategy.PATH,
|
|
52
|
+
no_cdn: bool = False,
|
|
46
53
|
websocket_endpoint_path: Optional[str] = None,
|
|
47
54
|
) -> None:
|
|
48
|
-
self.index = "index.html"
|
|
49
|
-
self.manifest_json = "manifest.json"
|
|
55
|
+
self.index = ["index.html"]
|
|
56
|
+
self.manifest_json = ["manifest.json"]
|
|
57
|
+
self.font_manifest_json = ["assets", "FontManifest.json"]
|
|
50
58
|
self.__proxy_path = proxy_path
|
|
51
59
|
self.__assets_dir = assets_dir
|
|
52
60
|
self.__app_name = app_name
|
|
53
61
|
self.__app_short_name = app_short_name
|
|
54
62
|
self.__app_description = app_description
|
|
55
63
|
self.__web_renderer = web_renderer
|
|
56
|
-
self.__use_color_emoji = use_color_emoji
|
|
57
64
|
self.__route_url_strategy = route_url_strategy
|
|
65
|
+
self.__no_cdn = no_cdn
|
|
58
66
|
self.__websocket_endpoint_path = websocket_endpoint_path
|
|
59
67
|
self.__once = Once()
|
|
60
68
|
|
|
@@ -62,23 +70,23 @@ class FletStaticFiles(StaticFiles):
|
|
|
62
70
|
if env_web_renderer:
|
|
63
71
|
self.__web_renderer = WebRenderer(env_web_renderer)
|
|
64
72
|
|
|
65
|
-
env_use_color_emoji = get_bool_env_var("FLET_WEB_USE_COLOR_EMOJI")
|
|
66
|
-
if env_use_color_emoji is not None:
|
|
67
|
-
self.__use_color_emoji = env_use_color_emoji
|
|
68
|
-
|
|
69
73
|
env_route_url_strategy = os.getenv("FLET_WEB_ROUTE_URL_STRATEGY")
|
|
70
74
|
if env_route_url_strategy:
|
|
71
|
-
self.__route_url_strategy = env_route_url_strategy
|
|
75
|
+
self.__route_url_strategy = RouteUrlStrategy(env_route_url_strategy)
|
|
76
|
+
|
|
77
|
+
env_no_cdn = get_bool_env_var("FLET_WEB_NO_CDN")
|
|
78
|
+
if env_no_cdn is not None:
|
|
79
|
+
self.__no_cdn = env_no_cdn
|
|
72
80
|
|
|
73
81
|
logger.info(f"Web renderer configured: {self.__web_renderer}")
|
|
74
|
-
logger.info(f"Use color emoji: {self.__use_color_emoji}")
|
|
75
82
|
logger.info(f"Route URL strategy configured: {self.__route_url_strategy}")
|
|
83
|
+
logger.info(f"No CDN configured: {self.__no_cdn}")
|
|
76
84
|
|
|
77
85
|
async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
|
|
78
86
|
await self.__once.do(self.__config, scope["root_path"])
|
|
79
87
|
await super().__call__(scope, receive, send)
|
|
80
88
|
|
|
81
|
-
def lookup_path(self, path: str) ->
|
|
89
|
+
def lookup_path(self, path: str) -> tuple[str, Optional[os.stat_result]]:
|
|
82
90
|
"""Returns the index file when no match is found.
|
|
83
91
|
|
|
84
92
|
Args:
|
|
@@ -92,7 +100,7 @@ class FletStaticFiles(StaticFiles):
|
|
|
92
100
|
|
|
93
101
|
# if a file cannot be found
|
|
94
102
|
if stat_result is None:
|
|
95
|
-
return super().lookup_path(self.index)
|
|
103
|
+
return super().lookup_path(self.index[0])
|
|
96
104
|
|
|
97
105
|
return full_path, stat_result
|
|
98
106
|
|
|
@@ -125,33 +133,22 @@ class FletStaticFiles(StaticFiles):
|
|
|
125
133
|
|
|
126
134
|
logger.info(f"Assets dir: {self.__assets_dir}")
|
|
127
135
|
|
|
136
|
+
def copy_temp_web_file(paths: list[str]):
|
|
137
|
+
if self.__assets_dir and os.path.exists(
|
|
138
|
+
p := os.path.join(self.__assets_dir, *paths)
|
|
139
|
+
):
|
|
140
|
+
src_path = p
|
|
141
|
+
else:
|
|
142
|
+
src_path = os.path.join(web_dir, *paths)
|
|
143
|
+
dst_path = os.path.join(temp_dir, *paths)
|
|
144
|
+
Path(dst_path).parent.mkdir(parents=True, exist_ok=True)
|
|
145
|
+
shutil.copyfile(src_path, dst_path)
|
|
146
|
+
|
|
128
147
|
# copy index.html from assets_dir or web_dir
|
|
129
|
-
|
|
130
|
-
os.path.join(self.__assets_dir, self.index)
|
|
131
|
-
):
|
|
132
|
-
shutil.copyfile(
|
|
133
|
-
os.path.join(self.__assets_dir, self.index),
|
|
134
|
-
os.path.join(temp_dir, self.index),
|
|
135
|
-
)
|
|
136
|
-
else:
|
|
137
|
-
shutil.copyfile(
|
|
138
|
-
os.path.join(web_dir, self.index),
|
|
139
|
-
os.path.join(temp_dir, self.index),
|
|
140
|
-
)
|
|
148
|
+
copy_temp_web_file(self.index)
|
|
141
149
|
|
|
142
150
|
# copy manifest.json from assets_dir or web_dir
|
|
143
|
-
|
|
144
|
-
os.path.join(self.__assets_dir, self.manifest_json)
|
|
145
|
-
):
|
|
146
|
-
shutil.copyfile(
|
|
147
|
-
os.path.join(self.__assets_dir, self.manifest_json),
|
|
148
|
-
os.path.join(temp_dir, self.manifest_json),
|
|
149
|
-
)
|
|
150
|
-
else:
|
|
151
|
-
shutil.copyfile(
|
|
152
|
-
os.path.join(web_dir, self.manifest_json),
|
|
153
|
-
os.path.join(temp_dir, self.manifest_json),
|
|
154
|
-
)
|
|
151
|
+
copy_temp_web_file(self.manifest_json)
|
|
155
152
|
|
|
156
153
|
ws_path = self.__websocket_endpoint_path
|
|
157
154
|
if not ws_path:
|
|
@@ -160,23 +157,30 @@ class FletStaticFiles(StaticFiles):
|
|
|
160
157
|
|
|
161
158
|
# replace variables in index.html and manifest.json
|
|
162
159
|
patch_index_html(
|
|
163
|
-
index_path=os.path.join(temp_dir, self.index),
|
|
160
|
+
index_path=os.path.join(temp_dir, *self.index),
|
|
164
161
|
base_href=self.__app_mount_path,
|
|
165
162
|
websocket_endpoint_path=ws_path,
|
|
166
163
|
app_name=self.__app_name,
|
|
167
164
|
app_description=self.__app_description,
|
|
168
|
-
web_renderer=
|
|
169
|
-
use_color_emoji=self.__use_color_emoji,
|
|
165
|
+
web_renderer=self.__web_renderer,
|
|
170
166
|
route_url_strategy=self.__route_url_strategy,
|
|
167
|
+
no_cdn=self.__no_cdn,
|
|
171
168
|
)
|
|
172
169
|
|
|
173
170
|
patch_manifest_json(
|
|
174
|
-
manifest_path=os.path.join(temp_dir, self.manifest_json),
|
|
171
|
+
manifest_path=os.path.join(temp_dir, *self.manifest_json),
|
|
175
172
|
app_name=self.__app_name,
|
|
176
173
|
app_short_name=self.__app_short_name,
|
|
177
174
|
app_description=self.__app_description,
|
|
178
175
|
)
|
|
179
176
|
|
|
177
|
+
if self.__no_cdn:
|
|
178
|
+
# copy FontManifest.json from assets_dir or web_dir
|
|
179
|
+
copy_temp_web_file(self.font_manifest_json)
|
|
180
|
+
patch_font_manifest_json(
|
|
181
|
+
manifest_path=os.path.join(temp_dir, *self.font_manifest_json)
|
|
182
|
+
)
|
|
183
|
+
|
|
180
184
|
# set html=True to resolve the index even when no
|
|
181
185
|
# the base path is passed in
|
|
182
186
|
super().__init__(directory=temp_dir, packages=None, html=True, check_dir=True)
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import logging
|
|
3
|
-
from typing import Optional
|
|
3
|
+
from typing import Any, Optional, Union
|
|
4
4
|
|
|
5
5
|
import uvicorn
|
|
6
|
-
from flet.
|
|
6
|
+
from flet.controls.types import RouteUrlStrategy, WebRenderer
|
|
7
7
|
|
|
8
8
|
import flet_web.fastapi
|
|
9
9
|
import flet_web.fastapi as flet_fastapi
|
|
@@ -22,25 +22,27 @@ class WebServerHandle:
|
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
def get_fastapi_web_app(
|
|
25
|
-
|
|
25
|
+
main,
|
|
26
|
+
before_main,
|
|
26
27
|
page_name: str,
|
|
27
|
-
assets_dir,
|
|
28
|
-
upload_dir,
|
|
29
|
-
web_renderer:
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
assets_dir: str,
|
|
29
|
+
upload_dir: str,
|
|
30
|
+
web_renderer: WebRenderer = WebRenderer.AUTO,
|
|
31
|
+
route_url_strategy: RouteUrlStrategy = RouteUrlStrategy.PATH,
|
|
32
|
+
no_cdn: bool = False,
|
|
32
33
|
):
|
|
33
34
|
web_path = f"/{page_name.strip('/')}"
|
|
34
35
|
app = flet_web.fastapi.FastAPI()
|
|
35
36
|
app.mount(
|
|
36
37
|
web_path,
|
|
37
38
|
flet_web.fastapi.app(
|
|
38
|
-
|
|
39
|
+
main,
|
|
40
|
+
before_main=before_main,
|
|
39
41
|
upload_dir=upload_dir,
|
|
40
42
|
assets_dir=assets_dir,
|
|
41
|
-
web_renderer=web_renderer
|
|
42
|
-
use_color_emoji=use_color_emoji,
|
|
43
|
+
web_renderer=web_renderer,
|
|
43
44
|
route_url_strategy=route_url_strategy,
|
|
45
|
+
no_cdn=no_cdn,
|
|
44
46
|
),
|
|
45
47
|
)
|
|
46
48
|
|
|
@@ -48,21 +50,21 @@ def get_fastapi_web_app(
|
|
|
48
50
|
|
|
49
51
|
|
|
50
52
|
async def serve_fastapi_web_app(
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
main,
|
|
54
|
+
before_main,
|
|
55
|
+
host: str,
|
|
56
|
+
url_host: str,
|
|
57
|
+
port: int,
|
|
55
58
|
page_name: str,
|
|
56
|
-
assets_dir,
|
|
57
|
-
upload_dir,
|
|
58
|
-
web_renderer:
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
blocking,
|
|
62
|
-
on_startup,
|
|
63
|
-
log_level,
|
|
59
|
+
assets_dir: str,
|
|
60
|
+
upload_dir: str,
|
|
61
|
+
web_renderer: WebRenderer = WebRenderer.AUTO,
|
|
62
|
+
route_url_strategy: RouteUrlStrategy = RouteUrlStrategy.PATH,
|
|
63
|
+
no_cdn: bool = False,
|
|
64
|
+
blocking: bool = False,
|
|
65
|
+
on_startup: Optional[Any] = None,
|
|
66
|
+
log_level: Optional[Union[str, int]] = None,
|
|
64
67
|
):
|
|
65
|
-
|
|
66
68
|
web_path = f"/{page_name.strip('/')}"
|
|
67
69
|
page_url = f"http://{url_host}:{port}{web_path if web_path != '/' else ''}"
|
|
68
70
|
|
|
@@ -75,12 +77,13 @@ async def serve_fastapi_web_app(
|
|
|
75
77
|
app.mount(
|
|
76
78
|
web_path,
|
|
77
79
|
flet_web.fastapi.app(
|
|
78
|
-
|
|
80
|
+
main,
|
|
81
|
+
before_main=before_main,
|
|
79
82
|
upload_dir=upload_dir,
|
|
80
83
|
assets_dir=assets_dir,
|
|
81
|
-
web_renderer=web_renderer
|
|
82
|
-
use_color_emoji=use_color_emoji,
|
|
84
|
+
web_renderer=web_renderer,
|
|
83
85
|
route_url_strategy=route_url_strategy,
|
|
86
|
+
no_cdn=no_cdn,
|
|
84
87
|
),
|
|
85
88
|
)
|
|
86
89
|
config = uvicorn.Config(app, host=host, port=port, log_level=log_level)
|
flet_web/patch_index.py
CHANGED
|
@@ -3,7 +3,7 @@ import re
|
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
from typing import Optional
|
|
5
5
|
|
|
6
|
-
from flet.
|
|
6
|
+
from flet.controls.types import RouteUrlStrategy, WebRenderer
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
def patch_index_html(
|
|
@@ -16,64 +16,54 @@ def patch_index_html(
|
|
|
16
16
|
pyodide_pre: bool = False,
|
|
17
17
|
pyodide_script_path: str = "",
|
|
18
18
|
web_renderer: WebRenderer = WebRenderer.AUTO,
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
route_url_strategy: RouteUrlStrategy = RouteUrlStrategy.PATH,
|
|
20
|
+
no_cdn: bool = False,
|
|
21
21
|
):
|
|
22
|
-
with open(index_path,
|
|
22
|
+
with open(index_path, encoding="utf-8") as f:
|
|
23
23
|
index = f.read()
|
|
24
24
|
|
|
25
|
+
app_config = []
|
|
26
|
+
|
|
25
27
|
if pyodide and pyodide_script_path:
|
|
26
28
|
module_name = Path(pyodide_script_path).stem
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
f'<script>webRenderer="{web_renderer.value}";</script>',
|
|
39
|
-
)
|
|
29
|
+
app_config.append("flet.pyodide = true;")
|
|
30
|
+
app_config.append(f"flet.micropipIncludePre = {str(pyodide_pre).lower()};")
|
|
31
|
+
app_config.append(f'flet.pythonModuleName = "{module_name}";')
|
|
32
|
+
|
|
33
|
+
app_config.append(f"flet.noCdn={str(no_cdn).lower()};")
|
|
34
|
+
app_config.append(f'flet.webRenderer="{web_renderer.value}";')
|
|
35
|
+
app_config.append(f'flet.routeUrlStrategy="{route_url_strategy.value}";')
|
|
36
|
+
|
|
37
|
+
if websocket_endpoint_path:
|
|
38
|
+
app_config.append(f'flet.webSocketEndpoint="{websocket_endpoint_path}";')
|
|
39
|
+
|
|
40
40
|
index = index.replace(
|
|
41
|
-
"<!--
|
|
42
|
-
|
|
41
|
+
"<!-- fletAppConfig -->",
|
|
42
|
+
"<script>\n{}\n</script>".format("\n".join(app_config)),
|
|
43
43
|
)
|
|
44
|
-
index = index.replace("%FLET_ROUTE_URL_STRATEGY%", route_url_strategy)
|
|
45
44
|
|
|
46
45
|
if base_href:
|
|
47
46
|
base_url = base_href.strip("/").strip()
|
|
48
47
|
index = index.replace(
|
|
49
48
|
'<base href="/">',
|
|
50
|
-
'<base href="{}">'.format(
|
|
51
|
-
"/" if base_url == "" else "/{}/".format(base_url)
|
|
52
|
-
),
|
|
53
|
-
)
|
|
54
|
-
if websocket_endpoint_path:
|
|
55
|
-
index = re.sub(
|
|
56
|
-
r"\<meta name=\"flet-websocket-endpoint-path\" content=\"(.+)\">",
|
|
57
|
-
r'<meta name="flet-websocket-endpoint-path" content="{}">'.format(
|
|
58
|
-
websocket_endpoint_path
|
|
59
|
-
),
|
|
60
|
-
index,
|
|
49
|
+
'<base href="{}">'.format("/" if base_url == "" else f"/{base_url}/"),
|
|
61
50
|
)
|
|
51
|
+
|
|
62
52
|
if app_name:
|
|
63
53
|
index = re.sub(
|
|
64
54
|
r"\<meta name=\"apple-mobile-web-app-title\" content=\"(.+)\">",
|
|
65
|
-
|
|
55
|
+
rf'<meta name="apple-mobile-web-app-title" content="{app_name}">',
|
|
66
56
|
index,
|
|
67
57
|
)
|
|
68
58
|
index = re.sub(
|
|
69
59
|
r"\<title>(.+)</title>",
|
|
70
|
-
|
|
60
|
+
rf"<title>{app_name}</title>",
|
|
71
61
|
index,
|
|
72
62
|
)
|
|
73
63
|
if app_description:
|
|
74
64
|
index = re.sub(
|
|
75
65
|
r"\<meta name=\"description\" content=\"(.+)\">",
|
|
76
|
-
|
|
66
|
+
rf'<meta name="description" content="{app_description}">',
|
|
77
67
|
index,
|
|
78
68
|
)
|
|
79
69
|
|
|
@@ -89,7 +79,7 @@ def patch_manifest_json(
|
|
|
89
79
|
background_color: Optional[str] = None,
|
|
90
80
|
theme_color: Optional[str] = None,
|
|
91
81
|
):
|
|
92
|
-
with open(manifest_path,
|
|
82
|
+
with open(manifest_path, encoding="utf-8") as f:
|
|
93
83
|
manifest = json.loads(f.read())
|
|
94
84
|
|
|
95
85
|
if app_name:
|
|
@@ -110,3 +100,13 @@ def patch_manifest_json(
|
|
|
110
100
|
|
|
111
101
|
with open(manifest_path, "w", encoding="utf-8") as f:
|
|
112
102
|
f.write(json.dumps(manifest, indent=2))
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def patch_font_manifest_json(manifest_path: str):
|
|
106
|
+
with open(manifest_path, encoding="utf-8") as f:
|
|
107
|
+
manifest = json.loads(f.read())
|
|
108
|
+
|
|
109
|
+
manifest.append({"family": "Roboto", "fonts": [{"asset": "fonts/roboto.woff2"}]})
|
|
110
|
+
|
|
111
|
+
with open(manifest_path, "w", encoding="utf-8") as f:
|
|
112
|
+
f.write(json.dumps(manifest, indent=2))
|
flet_web/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
version = "0.
|
|
1
|
+
version = "0.70.0.dev5066"
|