flet-web 0.86.5__tar.gz → 1.0.0.dev0__tar.gz

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.
Files changed (25) hide show
  1. {flet_web-0.86.5 → flet_web-1.0.0.dev0}/PKG-INFO +2 -2
  2. {flet_web-0.86.5 → flet_web-1.0.0.dev0}/pyproject.toml +2 -2
  3. {flet_web-0.86.5 → flet_web-1.0.0.dev0}/src/flet_web/fastapi/app.py +6 -1
  4. {flet_web-0.86.5 → flet_web-1.0.0.dev0}/src/flet_web/fastapi/flet_app.py +11 -11
  5. {flet_web-0.86.5 → flet_web-1.0.0.dev0}/src/flet_web/fastapi/flet_static_files.py +34 -8
  6. {flet_web-0.86.5 → flet_web-1.0.0.dev0}/src/flet_web/patch_index.py +8 -1
  7. flet_web-1.0.0.dev0/src/flet_web/version.py +1 -0
  8. {flet_web-0.86.5 → flet_web-1.0.0.dev0}/src/flet_web.egg-info/PKG-INFO +2 -2
  9. {flet_web-0.86.5 → flet_web-1.0.0.dev0}/src/flet_web.egg-info/SOURCES.txt +2 -1
  10. {flet_web-0.86.5 → flet_web-1.0.0.dev0}/src/flet_web.egg-info/requires.txt +1 -1
  11. flet_web-1.0.0.dev0/tests/test_loading_logo.py +43 -0
  12. flet_web-0.86.5/src/flet_web/version.py +0 -1
  13. {flet_web-0.86.5 → flet_web-1.0.0.dev0}/README.md +0 -0
  14. {flet_web-0.86.5 → flet_web-1.0.0.dev0}/setup.cfg +0 -0
  15. {flet_web-0.86.5 → flet_web-1.0.0.dev0}/src/flet_web/__init__.py +0 -0
  16. {flet_web-0.86.5 → flet_web-1.0.0.dev0}/src/flet_web/fastapi/__init__.py +0 -0
  17. {flet_web-0.86.5 → flet_web-1.0.0.dev0}/src/flet_web/fastapi/flet_app_manager.py +0 -0
  18. {flet_web-0.86.5 → flet_web-1.0.0.dev0}/src/flet_web/fastapi/flet_fastapi.py +0 -0
  19. {flet_web-0.86.5 → flet_web-1.0.0.dev0}/src/flet_web/fastapi/flet_oauth.py +0 -0
  20. {flet_web-0.86.5 → flet_web-1.0.0.dev0}/src/flet_web/fastapi/flet_upload.py +0 -0
  21. {flet_web-0.86.5 → flet_web-1.0.0.dev0}/src/flet_web/fastapi/oauth_state.py +0 -0
  22. {flet_web-0.86.5 → flet_web-1.0.0.dev0}/src/flet_web/fastapi/serve_fastapi_web_app.py +0 -0
  23. {flet_web-0.86.5 → flet_web-1.0.0.dev0}/src/flet_web/uploads.py +0 -0
  24. {flet_web-0.86.5 → flet_web-1.0.0.dev0}/src/flet_web.egg-info/dependency_links.txt +0 -0
  25. {flet_web-0.86.5 → flet_web-1.0.0.dev0}/src/flet_web.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: flet-web
3
- Version: 0.86.5
3
+ Version: 1.0.0.dev0
4
4
  Summary: Flet web client in Flutter.
5
5
  Author-email: "Appveyor Systems Inc." <hello@flet.dev>
6
6
  License-Expression: Apache-2.0
@@ -9,7 +9,7 @@ Project-URL: Repository, https://github.com/flet-dev/flet
9
9
  Project-URL: Documentation, https://flet.dev/docs
10
10
  Requires-Python: >=3.10
11
11
  Description-Content-Type: text/markdown
12
- Requires-Dist: flet==0.86.5
12
+ Requires-Dist: flet==1.0.0.dev0
13
13
  Requires-Dist: fastapi>=0.115.12
14
14
  Requires-Dist: uvicorn[standard]>=0.35.0
15
15
 
@@ -1,13 +1,13 @@
1
1
  [project]
2
2
  name = "flet-web"
3
- version = "0.86.5"
3
+ version = "1.0.0.dev0"
4
4
  description = "Flet web client in Flutter."
5
5
  authors = [{ name = "Appveyor Systems Inc.", email = "hello@flet.dev" }]
6
6
  license = "Apache-2.0"
7
7
  readme = "README.md"
8
8
  requires-python = ">=3.10"
9
9
  dependencies = [
10
- "flet==0.86.5",
10
+ "flet==1.0.0.dev0",
11
11
  "fastapi >=0.115.12",
12
12
  "uvicorn[standard] >=0.35.0"
13
13
  ]
@@ -46,7 +46,8 @@ def app(
46
46
  instance :class:`~flet.Page`.
47
47
  before_main: Called after `Page` was created, but before calling `main`.
48
48
  proxy_path: URL prefix when the app is mounted under a proxy.
49
- assets_dir: an absolute path to app's assets directory.
49
+ assets_dir: path to app's assets directory. A relative path is resolved
50
+ against the current working directory.
50
51
  app_name: PWA application name.
51
52
  app_short_name: PWA application short name.
52
53
  app_description: PWA application description.
@@ -64,6 +65,10 @@ def app(
64
65
  redirecting to OAuth callback URL.
65
66
  """
66
67
 
68
+ env_assets_dir = os.getenv("FLET_ASSETS_DIR")
69
+ if env_assets_dir:
70
+ assets_dir = env_assets_dir
71
+
67
72
  env_upload_dir = os.getenv("FLET_UPLOAD_DIR")
68
73
  if env_upload_dir:
69
74
  upload_dir = env_upload_dir
@@ -18,10 +18,10 @@ from flet.controls.context import _context_page, context
18
18
  from flet.controls.exceptions import FletPageDisconnectedException
19
19
  from flet.messaging.connection import Connection
20
20
  from flet.messaging.protocol import (
21
- ClientAction,
22
- ClientMessage,
23
21
  ControlEventBody,
24
22
  InvokeMethodResponseBody,
23
+ Message,
24
+ MessageAction,
25
25
  RegisterClientRequestBody,
26
26
  RegisterClientResponseBody,
27
27
  UpdateControlPropsBody,
@@ -259,7 +259,7 @@ class FletApp(Connection):
259
259
  async def __on_message(self, data: Any):
260
260
  """
261
261
  Handle one decoded client message and dispatch
262
- by `ClientAction`.
262
+ by `MessageAction`.
263
263
 
264
264
  Args:
265
265
  data: Decoded message payload from msgpack transport.
@@ -268,11 +268,11 @@ class FletApp(Connection):
268
268
  RuntimeError: If message action is unknown.
269
269
  """
270
270
 
271
- action = ClientAction(data[0])
271
+ action = MessageAction(data[0])
272
272
  body = data[1]
273
273
  transport_log.debug(f"_on_message: {action} {body}")
274
274
  task = None
275
- if action == ClientAction.REGISTER_CLIENT:
275
+ if action == MessageAction.REGISTER_CLIENT:
276
276
  req = RegisterClientRequestBody(**body)
277
277
 
278
278
  new_session = False
@@ -335,8 +335,8 @@ class FletApp(Connection):
335
335
 
336
336
  # register response
337
337
  self.send_message(
338
- ClientMessage(
339
- ClientAction.REGISTER_CLIENT,
338
+ Message(
339
+ MessageAction.REGISTER_CLIENT,
340
340
  RegisterClientResponseBody(
341
341
  session_id=self.__session.id,
342
342
  page_patch=self.__session.get_page_patch()
@@ -379,17 +379,17 @@ class FletApp(Connection):
379
379
  }
380
380
  )
381
381
 
382
- elif action == ClientAction.CONTROL_EVENT:
382
+ elif action == MessageAction.CONTROL_EVENT:
383
383
  req = ControlEventBody(**body)
384
384
  task = asyncio.create_task(
385
385
  self.__session.dispatch_event(req.target, req.name, req.data)
386
386
  )
387
387
 
388
- elif action == ClientAction.UPDATE_CONTROL_PROPS:
388
+ elif action == MessageAction.UPDATE_CONTROL_PROPS:
389
389
  req = UpdateControlPropsBody(**body)
390
390
  self.__session.apply_patch(req.id, req.props)
391
391
 
392
- elif action == ClientAction.INVOKE_METHOD:
392
+ elif action == MessageAction.INVOKE_METHOD:
393
393
  req = InvokeMethodResponseBody(**body)
394
394
  self.__session.handle_invoke_method_results(
395
395
  req.control_id, req.call_id, req.result, req.error
@@ -403,7 +403,7 @@ class FletApp(Connection):
403
403
  self.__running_tasks.add(task)
404
404
  task.add_done_callback(self.__running_tasks.discard)
405
405
 
406
- def send_message(self, message: ClientMessage):
406
+ def send_message(self, message: Message):
407
407
  """
408
408
  Serialize and enqueue a server message for transport to the client.
409
409
 
@@ -28,12 +28,44 @@ mimetypes.add_type("text/javascript", ".mjs")
28
28
  mimetypes.add_type("application/wasm", ".wasm")
29
29
 
30
30
 
31
+ def resolve_assets_dir(assets_dir: Optional[str]) -> Optional[str]:
32
+ """
33
+ Resolve an app's assets directory to an existing absolute path.
34
+
35
+ A relative path is resolved against the current working directory, which
36
+ matches `ft.run(export_asgi_app=True)` - the other way a Flet app is served
37
+ from a server process started externally (e.g. by `uvicorn`).
38
+
39
+ Args:
40
+ assets_dir: Path to the app's assets directory, absolute or relative.
41
+
42
+ Returns:
43
+ The resolved absolute path, or `None` if `assets_dir` was not set or
44
+ does not exist.
45
+ """
46
+
47
+ if not assets_dir:
48
+ return None
49
+
50
+ path = Path(assets_dir)
51
+ if not path.is_absolute():
52
+ path = Path.cwd().joinpath(path)
53
+ resolved = str(path.resolve())
54
+
55
+ if not os.path.exists(resolved):
56
+ logger.warning(f"assets_dir does not exist: {resolved}")
57
+ return None
58
+
59
+ return resolved
60
+
61
+
31
62
  class FletStaticFiles(StaticFiles):
32
63
  """
33
64
  Serve Flet app static files.
34
65
 
35
66
  Args:
36
- assets_dir: An absolute path to app's assets directory.
67
+ assets_dir: Path to app's assets directory. A relative path is resolved
68
+ against the current working directory.
37
69
  app_name: PWA application name.
38
70
  app_short_name: PWA application short name.
39
71
  app_description: PWA application description.
@@ -151,13 +183,7 @@ class FletStaticFiles(StaticFiles):
151
183
  raise RuntimeError(f"Web root path not found: {web_dir}")
152
184
 
153
185
  # user-defined assets
154
- if self.__assets_dir:
155
- if not Path(self.__assets_dir).is_absolute():
156
- logger.warning("assets_dir must be absolute path.")
157
- self.__assets_dir = None
158
- elif not os.path.exists(self.__assets_dir):
159
- logger.info(f"assets_dir does not exist: {self.__assets_dir}")
160
- self.__assets_dir = None
186
+ self.__assets_dir = resolve_assets_dir(self.__assets_dir)
161
187
 
162
188
  logger.info(f"Assets dir: {self.__assets_dir}")
163
189
 
@@ -70,7 +70,7 @@ def patch_index_html(
70
70
  # loads it via dynamic `import()`. We can no longer use `.js` because
71
71
  # Pyodide >= 0.29 throws "Classic web workers are not supported" inside
72
72
  # any worker that has `importScripts` available — only classic workers
73
- # have it. All supported Pyodide versions (0.27.7 / 0.29.4 / 314.0.0)
73
+ # have it. All supported Pyodide versions (0.27.7 / 0.29.4 / 314.0.6)
74
74
  # ship `pyodide.mjs`.
75
75
  if pyodide_version:
76
76
  if no_cdn:
@@ -81,6 +81,13 @@ def patch_index_html(
81
81
  )
82
82
  app_config.append(f'flet.pyodideUrl="{pyodide_url}";')
83
83
 
84
+ # Only pinned when bundling: left unset, `flutter_bootstrap.js` lets
85
+ # Flutter resolve CanvasKit from gstatic and the Noto fallback fonts from
86
+ # Google Fonts, and `flet build`/`flet publish` skip shipping local copies.
87
+ if no_cdn:
88
+ app_config.append(f'flet.canvasKitBaseUrl="{base_url}canvaskit/";')
89
+ app_config.append('flet.fontFallbackBaseUrl="assets/fonts/";')
90
+
84
91
  app_config.append(f"flet.noCdn={str(no_cdn).lower()};")
85
92
  app_config.append(f'flet.webRenderer="{web_renderer.value}";')
86
93
  app_config.append(f'flet.routeUrlStrategy="{route_url_strategy.value}";')
@@ -0,0 +1 @@
1
+ version = "1.0.0.dev0"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: flet-web
3
- Version: 0.86.5
3
+ Version: 1.0.0.dev0
4
4
  Summary: Flet web client in Flutter.
5
5
  Author-email: "Appveyor Systems Inc." <hello@flet.dev>
6
6
  License-Expression: Apache-2.0
@@ -9,7 +9,7 @@ Project-URL: Repository, https://github.com/flet-dev/flet
9
9
  Project-URL: Documentation, https://flet.dev/docs
10
10
  Requires-Python: >=3.10
11
11
  Description-Content-Type: text/markdown
12
- Requires-Dist: flet==0.86.5
12
+ Requires-Dist: flet==1.0.0.dev0
13
13
  Requires-Dist: fastapi>=0.115.12
14
14
  Requires-Dist: uvicorn[standard]>=0.35.0
15
15
 
@@ -18,4 +18,5 @@ src/flet_web/fastapi/flet_oauth.py
18
18
  src/flet_web/fastapi/flet_static_files.py
19
19
  src/flet_web/fastapi/flet_upload.py
20
20
  src/flet_web/fastapi/oauth_state.py
21
- src/flet_web/fastapi/serve_fastapi_web_app.py
21
+ src/flet_web/fastapi/serve_fastapi_web_app.py
22
+ tests/test_loading_logo.py
@@ -1,3 +1,3 @@
1
- flet==0.86.5
1
+ flet==1.0.0.dev0
2
2
  fastapi>=0.115.12
3
3
  uvicorn[standard]>=0.35.0
@@ -0,0 +1,43 @@
1
+ import importlib
2
+ import shutil
3
+ from pathlib import Path
4
+
5
+ import pytest
6
+ from fastapi import FastAPI
7
+ from fastapi.testclient import TestClient
8
+
9
+ static_files = importlib.import_module("flet_web.fastapi.flet_static_files")
10
+ CLIENT_WEB = Path(__file__).resolve().parents[5] / "client" / "web"
11
+
12
+
13
+ @pytest.mark.parametrize("custom_logo", [False, True])
14
+ def test_dynamic_loading_logo_respects_assets_override(
15
+ tmp_path, monkeypatch, custom_logo
16
+ ):
17
+ web = tmp_path / "web"
18
+ shutil.copytree(CLIENT_WEB, web)
19
+ # Flutter substitutes this token before packaging the dynamic client.
20
+ index = web / "index.html"
21
+ index.write_text(index.read_text().replace("$FLUTTER_BASE_HREF", "/"))
22
+ monkeypatch.setattr(static_files, "get_package_web_dir", lambda: str(web))
23
+ assets = tmp_path / "assets"
24
+ assets.mkdir()
25
+ relative = Path("icons/loading-animation.png")
26
+ expected = (CLIENT_WEB / relative).read_bytes()
27
+ if custom_logo:
28
+ # Serving must preserve the user's bytes instead of regenerating the logo.
29
+ expected = b"custom loading logo"
30
+ (assets / "icons").mkdir()
31
+ (assets / relative).write_bytes(expected)
32
+
33
+ app = FastAPI()
34
+ app.mount("/demo", static_files.FletStaticFiles(assets_dir=str(assets)))
35
+ with TestClient(app) as client:
36
+ page = client.get("/demo/nested/route")
37
+ assert page.status_code == 200
38
+ assert '<base href="/demo/">' in page.text
39
+ assert 'src="icons/loading-animation.png"' in page.text
40
+ assert "@keyframes" not in page.text
41
+ logo = client.get("/demo/icons/loading-animation.png")
42
+ assert logo.status_code == 200
43
+ assert logo.content == expected
@@ -1 +0,0 @@
1
- version = "0.86.5"
File without changes
File without changes