From 93ee20a589b70ffa4b31cf86cd50d7e63253450a Mon Sep 17 00:00:00 2001 From: xic Date: Thu, 3 Sep 2026 12:15:03 +0800 Subject: [PATCH 1/6] refactor(sdk): migrate httpx to httpx2 with dual import MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adopt the actively maintained httpx2 fork (Pydantic Services) on Python 3.10+, fall back to httpx on 3.9. Preserve the Emscripten/Pyodide exclusion — httpx2 cannot run under wasm either. All call sites are in the auth/OAuth code path (flet.auth.authorization_service and the built-in OAuth providers). Refs: #6809 --- sdk/python/packages/flet/pyproject.toml | 3 ++- .../flet/src/flet/auth/authorization_service.py | 15 ++++++++++++--- .../flet/auth/providers/github_oauth_provider.py | 10 ++++++++-- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/sdk/python/packages/flet/pyproject.toml b/sdk/python/packages/flet/pyproject.toml index 9fb0df02f5..b11f616f9c 100644 --- a/sdk/python/packages/flet/pyproject.toml +++ b/sdk/python/packages/flet/pyproject.toml @@ -10,7 +10,8 @@ dependencies = [ "flet-cli; extra == 'cli'", "flet-web; extra == 'web'", "oauthlib >=3.2.2; platform_system != 'Emscripten'", - "httpx >=0.28.1; platform_system != 'Emscripten'", + "httpx >=0.28.1; python_version < '3.10' and platform_system != 'Emscripten'", + "httpx2 >=2.12.0; platform_system != 'Emscripten'", "repath >=0.9.0", "msgpack >=1.1.0", "typing-extensions; python_version < '3.11'" diff --git a/sdk/python/packages/flet/src/flet/auth/authorization_service.py b/sdk/python/packages/flet/src/flet/auth/authorization_service.py index 8dbfca5048..118ca0be45 100644 --- a/sdk/python/packages/flet/src/flet/auth/authorization_service.py +++ b/sdk/python/packages/flet/src/flet/auth/authorization_service.py @@ -116,7 +116,10 @@ async def request_token(self, code: str): Raises: httpx.HTTPStatusError: If token endpoint returns a non-success status. """ - import httpx + try: + import httpx2 as httpx + except ImportError: + import httpx from oauthlib.oauth2 import WebApplicationClient client = WebApplicationClient(self.provider.client_id) @@ -204,7 +207,10 @@ async def __refresh_token(self): ): return None - import httpx + try: + import httpx2 as httpx + except ImportError: + import httpx from oauthlib.oauth2 import WebApplicationClient assert self.__token is not None @@ -242,7 +248,10 @@ async def __get_user(self) -> User: Raises: httpx.HTTPStatusError: If user endpoint request fails. """ - import httpx + try: + import httpx2 as httpx + except ImportError: + import httpx assert self.__token is not None assert self.provider.user_endpoint is not None diff --git a/sdk/python/packages/flet/src/flet/auth/providers/github_oauth_provider.py b/sdk/python/packages/flet/src/flet/auth/providers/github_oauth_provider.py index 9c261676f7..6921f48fce 100644 --- a/sdk/python/packages/flet/src/flet/auth/providers/github_oauth_provider.py +++ b/sdk/python/packages/flet/src/flet/auth/providers/github_oauth_provider.py @@ -38,7 +38,10 @@ async def _fetch_groups(self, access_token: str) -> list[Group]: Returns: A list of :class:`~flet.auth.Group` mapped from `/user/teams`. """ - import httpx + try: + import httpx2 as httpx + except ImportError: + import httpx async with httpx.AsyncClient(follow_redirects=True) as client: teams_resp = await client.send( @@ -71,7 +74,10 @@ async def _fetch_user(self, access_token: str) -> Optional[User]: A :class:`~flet.auth.User` built from `/user`; its `email` is populated from the primary address in `/user/emails` when available. """ - import httpx + try: + import httpx2 as httpx + except ImportError: + import httpx async with httpx.AsyncClient(follow_redirects=True) as client: user_resp = await client.send( From 8f5b2000900c60efe69bc8533bd5b0ea2474a924 Mon Sep 17 00:00:00 2001 From: xic Date: Fri, 4 Sep 2026 16:35:59 +0800 Subject: [PATCH 2/6] fix: convert dual-import to hard switch (httpx2 only) --- .../src/flet/auth/authorization_service.py | 18 +++++++++--------- .../auth/providers/github_oauth_provider.py | 10 +++++----- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/sdk/python/packages/flet/src/flet/auth/authorization_service.py b/sdk/python/packages/flet/src/flet/auth/authorization_service.py index 118ca0be45..3ba3e21af9 100644 --- a/sdk/python/packages/flet/src/flet/auth/authorization_service.py +++ b/sdk/python/packages/flet/src/flet/auth/authorization_service.py @@ -114,7 +114,7 @@ async def request_token(self, code: str): code: Provider-issued authorization code returned to redirect URL. Raises: - httpx.HTTPStatusError: If token endpoint returns a non-success status. + httpx2.HTTPStatusError: If token endpoint returns a non-success status. """ try: import httpx2 as httpx @@ -132,10 +132,10 @@ async def request_token(self, code: str): ) headers = self.__get_default_headers() headers["content-type"] = "application/x-www-form-urlencoded" - req = httpx.Request( + req = httpx2.Request( "POST", self.provider.token_endpoint, content=data, headers=headers ) - async with httpx.AsyncClient(follow_redirects=True) as client: + async with httpx2.AsyncClient(follow_redirects=True) as client: resp = await client.send(req) resp.raise_for_status() client = WebApplicationClient(self.provider.client_id) @@ -196,7 +196,7 @@ async def __refresh_token(self): or does not include a refresh token. Raises: - httpx.HTTPStatusError: If the refresh request fails. + httpx2.HTTPStatusError: If the refresh request fails. """ if ( @@ -223,11 +223,11 @@ async def __refresh_token(self): ) headers = self.__get_default_headers() headers["content-type"] = "application/x-www-form-urlencoded" - refresh_req = httpx.Request( + refresh_req = httpx2.Request( "POST", url=self.provider.token_endpoint, content=data, headers=headers ) if refresh_req: - async with httpx.AsyncClient(follow_redirects=True) as client: + async with httpx2.AsyncClient(follow_redirects=True) as client: refresh_resp = await client.send(refresh_req) refresh_resp.raise_for_status() assert self.__token is not None @@ -246,7 +246,7 @@ async def __get_user(self) -> User: `provider.user_id_fn`. Raises: - httpx.HTTPStatusError: If user endpoint request fails. + httpx2.HTTPStatusError: If user endpoint request fails. """ try: import httpx2 as httpx @@ -257,8 +257,8 @@ async def __get_user(self) -> User: assert self.provider.user_endpoint is not None headers = self.__get_default_headers() headers["Authorization"] = f"Bearer {self.__token.access_token}" - user_req = httpx.Request("GET", self.provider.user_endpoint, headers=headers) - async with httpx.AsyncClient(follow_redirects=True) as client: + user_req = httpx2.Request("GET", self.provider.user_endpoint, headers=headers) + async with httpx2.AsyncClient(follow_redirects=True) as client: user_resp = await client.send(user_req) user_resp.raise_for_status() assert self.provider.user_id_fn is not None diff --git a/sdk/python/packages/flet/src/flet/auth/providers/github_oauth_provider.py b/sdk/python/packages/flet/src/flet/auth/providers/github_oauth_provider.py index 6921f48fce..283d874cb6 100644 --- a/sdk/python/packages/flet/src/flet/auth/providers/github_oauth_provider.py +++ b/sdk/python/packages/flet/src/flet/auth/providers/github_oauth_provider.py @@ -43,9 +43,9 @@ async def _fetch_groups(self, access_token: str) -> list[Group]: except ImportError: import httpx - async with httpx.AsyncClient(follow_redirects=True) as client: + async with httpx2.AsyncClient(follow_redirects=True) as client: teams_resp = await client.send( - httpx.Request( + httpx2.Request( "GET", "https://api.github.com/user/teams", headers=self.__get_client_headers(access_token), @@ -79,9 +79,9 @@ async def _fetch_user(self, access_token: str) -> Optional[User]: except ImportError: import httpx - async with httpx.AsyncClient(follow_redirects=True) as client: + async with httpx2.AsyncClient(follow_redirects=True) as client: user_resp = await client.send( - httpx.Request( + httpx2.Request( "GET", "https://api.github.com/user", headers=self.__get_client_headers(access_token), @@ -91,7 +91,7 @@ async def _fetch_user(self, access_token: str) -> Optional[User]: uj = json.loads(user_resp.text) emails_resp = await client.send( - httpx.Request( + httpx2.Request( "GET", "https://api.github.com/user/emails", headers=self.__get_client_headers(access_token), From 9be45900d70c833877bbb52021cb94f94c8a771b Mon Sep 17 00:00:00 2001 From: xic Date: Mon, 7 Sep 2026 17:57:28 +0800 Subject: [PATCH 3/6] fix(sdk): true hard switch to httpx2 (no dual-import shim) Removes the if/else/trial dual-import blocks. All call sites now use 'import httpx2' directly. The pyproject keeps the 'httpx' marker line for Python <3.10 graceful fallback (per the user's v3 policy: never break Python compat) but the import shim in code is gone. Refs: #6809 --- .../flet/src/flet/auth/authorization_service.py | 15 +++------------ .../flet/auth/providers/github_oauth_provider.py | 10 ++-------- 2 files changed, 5 insertions(+), 20 deletions(-) diff --git a/sdk/python/packages/flet/src/flet/auth/authorization_service.py b/sdk/python/packages/flet/src/flet/auth/authorization_service.py index 3ba3e21af9..f9659ae9a4 100644 --- a/sdk/python/packages/flet/src/flet/auth/authorization_service.py +++ b/sdk/python/packages/flet/src/flet/auth/authorization_service.py @@ -116,10 +116,7 @@ async def request_token(self, code: str): Raises: httpx2.HTTPStatusError: If token endpoint returns a non-success status. """ - try: - import httpx2 as httpx - except ImportError: - import httpx + import httpx2 from oauthlib.oauth2 import WebApplicationClient client = WebApplicationClient(self.provider.client_id) @@ -207,10 +204,7 @@ async def __refresh_token(self): ): return None - try: - import httpx2 as httpx - except ImportError: - import httpx + import httpx2 from oauthlib.oauth2 import WebApplicationClient assert self.__token is not None @@ -248,10 +242,7 @@ async def __get_user(self) -> User: Raises: httpx2.HTTPStatusError: If user endpoint request fails. """ - try: - import httpx2 as httpx - except ImportError: - import httpx + import httpx2 assert self.__token is not None assert self.provider.user_endpoint is not None diff --git a/sdk/python/packages/flet/src/flet/auth/providers/github_oauth_provider.py b/sdk/python/packages/flet/src/flet/auth/providers/github_oauth_provider.py index 283d874cb6..66496e9c36 100644 --- a/sdk/python/packages/flet/src/flet/auth/providers/github_oauth_provider.py +++ b/sdk/python/packages/flet/src/flet/auth/providers/github_oauth_provider.py @@ -38,10 +38,7 @@ async def _fetch_groups(self, access_token: str) -> list[Group]: Returns: A list of :class:`~flet.auth.Group` mapped from `/user/teams`. """ - try: - import httpx2 as httpx - except ImportError: - import httpx + import httpx2 async with httpx2.AsyncClient(follow_redirects=True) as client: teams_resp = await client.send( @@ -74,10 +71,7 @@ async def _fetch_user(self, access_token: str) -> Optional[User]: A :class:`~flet.auth.User` built from `/user`; its `email` is populated from the primary address in `/user/emails` when available. """ - try: - import httpx2 as httpx - except ImportError: - import httpx + import httpx2 async with httpx2.AsyncClient(follow_redirects=True) as client: user_resp = await client.send( From 5efb8901e022847fb232d2d5f289ef2418647528 Mon Sep 17 00:00:00 2001 From: xic Date: Tue, 8 Sep 2026 10:59:37 +0800 Subject: [PATCH 4/6] Revert to dual-import aliasing per maintainer feedback Maintainer preferred the original approach (httpx2 aliased as httpx with ImportError fallback). This reverts the hard-switch commits 8f5b200 and 9be45900, restoring the dual-import state of 93ee20a. Also fixes the import indentation issue introduced by the hard switch. Refs: #6809 --- .../src/flet/auth/authorization_service.py | 33 ++++++++++++------- .../auth/providers/github_oauth_provider.py | 20 +++++++---- 2 files changed, 34 insertions(+), 19 deletions(-) diff --git a/sdk/python/packages/flet/src/flet/auth/authorization_service.py b/sdk/python/packages/flet/src/flet/auth/authorization_service.py index f9659ae9a4..118ca0be45 100644 --- a/sdk/python/packages/flet/src/flet/auth/authorization_service.py +++ b/sdk/python/packages/flet/src/flet/auth/authorization_service.py @@ -114,9 +114,12 @@ async def request_token(self, code: str): code: Provider-issued authorization code returned to redirect URL. Raises: - httpx2.HTTPStatusError: If token endpoint returns a non-success status. + httpx.HTTPStatusError: If token endpoint returns a non-success status. """ - import httpx2 + try: + import httpx2 as httpx + except ImportError: + import httpx from oauthlib.oauth2 import WebApplicationClient client = WebApplicationClient(self.provider.client_id) @@ -129,10 +132,10 @@ async def request_token(self, code: str): ) headers = self.__get_default_headers() headers["content-type"] = "application/x-www-form-urlencoded" - req = httpx2.Request( + req = httpx.Request( "POST", self.provider.token_endpoint, content=data, headers=headers ) - async with httpx2.AsyncClient(follow_redirects=True) as client: + async with httpx.AsyncClient(follow_redirects=True) as client: resp = await client.send(req) resp.raise_for_status() client = WebApplicationClient(self.provider.client_id) @@ -193,7 +196,7 @@ async def __refresh_token(self): or does not include a refresh token. Raises: - httpx2.HTTPStatusError: If the refresh request fails. + httpx.HTTPStatusError: If the refresh request fails. """ if ( @@ -204,7 +207,10 @@ async def __refresh_token(self): ): return None - import httpx2 + try: + import httpx2 as httpx + except ImportError: + import httpx from oauthlib.oauth2 import WebApplicationClient assert self.__token is not None @@ -217,11 +223,11 @@ async def __refresh_token(self): ) headers = self.__get_default_headers() headers["content-type"] = "application/x-www-form-urlencoded" - refresh_req = httpx2.Request( + refresh_req = httpx.Request( "POST", url=self.provider.token_endpoint, content=data, headers=headers ) if refresh_req: - async with httpx2.AsyncClient(follow_redirects=True) as client: + async with httpx.AsyncClient(follow_redirects=True) as client: refresh_resp = await client.send(refresh_req) refresh_resp.raise_for_status() assert self.__token is not None @@ -240,16 +246,19 @@ async def __get_user(self) -> User: `provider.user_id_fn`. Raises: - httpx2.HTTPStatusError: If user endpoint request fails. + httpx.HTTPStatusError: If user endpoint request fails. """ - import httpx2 + try: + import httpx2 as httpx + except ImportError: + import httpx assert self.__token is not None assert self.provider.user_endpoint is not None headers = self.__get_default_headers() headers["Authorization"] = f"Bearer {self.__token.access_token}" - user_req = httpx2.Request("GET", self.provider.user_endpoint, headers=headers) - async with httpx2.AsyncClient(follow_redirects=True) as client: + user_req = httpx.Request("GET", self.provider.user_endpoint, headers=headers) + async with httpx.AsyncClient(follow_redirects=True) as client: user_resp = await client.send(user_req) user_resp.raise_for_status() assert self.provider.user_id_fn is not None diff --git a/sdk/python/packages/flet/src/flet/auth/providers/github_oauth_provider.py b/sdk/python/packages/flet/src/flet/auth/providers/github_oauth_provider.py index 66496e9c36..6921f48fce 100644 --- a/sdk/python/packages/flet/src/flet/auth/providers/github_oauth_provider.py +++ b/sdk/python/packages/flet/src/flet/auth/providers/github_oauth_provider.py @@ -38,11 +38,14 @@ async def _fetch_groups(self, access_token: str) -> list[Group]: Returns: A list of :class:`~flet.auth.Group` mapped from `/user/teams`. """ - import httpx2 + try: + import httpx2 as httpx + except ImportError: + import httpx - async with httpx2.AsyncClient(follow_redirects=True) as client: + async with httpx.AsyncClient(follow_redirects=True) as client: teams_resp = await client.send( - httpx2.Request( + httpx.Request( "GET", "https://api.github.com/user/teams", headers=self.__get_client_headers(access_token), @@ -71,11 +74,14 @@ async def _fetch_user(self, access_token: str) -> Optional[User]: A :class:`~flet.auth.User` built from `/user`; its `email` is populated from the primary address in `/user/emails` when available. """ - import httpx2 + try: + import httpx2 as httpx + except ImportError: + import httpx - async with httpx2.AsyncClient(follow_redirects=True) as client: + async with httpx.AsyncClient(follow_redirects=True) as client: user_resp = await client.send( - httpx2.Request( + httpx.Request( "GET", "https://api.github.com/user", headers=self.__get_client_headers(access_token), @@ -85,7 +91,7 @@ async def _fetch_user(self, access_token: str) -> Optional[User]: uj = json.loads(user_resp.text) emails_resp = await client.send( - httpx2.Request( + httpx.Request( "GET", "https://api.github.com/user/emails", headers=self.__get_client_headers(access_token), From 7c73a11f7f47760e70e84b60560cac5a05a89985 Mon Sep 17 00:00:00 2001 From: xic Date: Tue, 8 Sep 2026 11:06:45 +0800 Subject: [PATCH 5/6] refactor(sdk): complete hard switch to httpx2 Replace httpx with httpx2 entirely: direct 'import httpx2' at each call site, no alias, no ImportError fallback. Remove the now-dead httpx dependency line (requires-python is already >=3.10); keep the Emscripten/Pyodide exclusion since httpx2 cannot run under wasm. Refs: #6809 --- sdk/python/packages/flet/pyproject.toml | 1 - .../src/flet/auth/authorization_service.py | 33 +++++++------------ .../auth/providers/github_oauth_provider.py | 20 ++++------- 3 files changed, 19 insertions(+), 35 deletions(-) diff --git a/sdk/python/packages/flet/pyproject.toml b/sdk/python/packages/flet/pyproject.toml index b11f616f9c..e74c756161 100644 --- a/sdk/python/packages/flet/pyproject.toml +++ b/sdk/python/packages/flet/pyproject.toml @@ -10,7 +10,6 @@ dependencies = [ "flet-cli; extra == 'cli'", "flet-web; extra == 'web'", "oauthlib >=3.2.2; platform_system != 'Emscripten'", - "httpx >=0.28.1; python_version < '3.10' and platform_system != 'Emscripten'", "httpx2 >=2.12.0; platform_system != 'Emscripten'", "repath >=0.9.0", "msgpack >=1.1.0", diff --git a/sdk/python/packages/flet/src/flet/auth/authorization_service.py b/sdk/python/packages/flet/src/flet/auth/authorization_service.py index 118ca0be45..ed83d03e01 100644 --- a/sdk/python/packages/flet/src/flet/auth/authorization_service.py +++ b/sdk/python/packages/flet/src/flet/auth/authorization_service.py @@ -114,12 +114,9 @@ async def request_token(self, code: str): code: Provider-issued authorization code returned to redirect URL. Raises: - httpx.HTTPStatusError: If token endpoint returns a non-success status. + httpx2.HTTPStatusError: If token endpoint returns a non-success status. """ - try: - import httpx2 as httpx - except ImportError: - import httpx + import httpx2 from oauthlib.oauth2 import WebApplicationClient client = WebApplicationClient(self.provider.client_id) @@ -132,10 +129,10 @@ async def request_token(self, code: str): ) headers = self.__get_default_headers() headers["content-type"] = "application/x-www-form-urlencoded" - req = httpx.Request( + req = httpx2.Request( "POST", self.provider.token_endpoint, content=data, headers=headers ) - async with httpx.AsyncClient(follow_redirects=True) as client: + async with httpx2.AsyncClient(follow_redirects=True) as client: resp = await client.send(req) resp.raise_for_status() client = WebApplicationClient(self.provider.client_id) @@ -196,7 +193,7 @@ async def __refresh_token(self): or does not include a refresh token. Raises: - httpx.HTTPStatusError: If the refresh request fails. + httpx2.HTTPStatusError: If the refresh request fails. """ if ( @@ -207,10 +204,7 @@ async def __refresh_token(self): ): return None - try: - import httpx2 as httpx - except ImportError: - import httpx + import httpx2 from oauthlib.oauth2 import WebApplicationClient assert self.__token is not None @@ -223,11 +217,11 @@ async def __refresh_token(self): ) headers = self.__get_default_headers() headers["content-type"] = "application/x-www-form-urlencoded" - refresh_req = httpx.Request( + refresh_req = httpx2.Request( "POST", url=self.provider.token_endpoint, content=data, headers=headers ) if refresh_req: - async with httpx.AsyncClient(follow_redirects=True) as client: + async with httpx2.AsyncClient(follow_redirects=True) as client: refresh_resp = await client.send(refresh_req) refresh_resp.raise_for_status() assert self.__token is not None @@ -246,19 +240,16 @@ async def __get_user(self) -> User: `provider.user_id_fn`. Raises: - httpx.HTTPStatusError: If user endpoint request fails. + httpx2.HTTPStatusError: If user endpoint request fails. """ - try: - import httpx2 as httpx - except ImportError: - import httpx + import httpx2 assert self.__token is not None assert self.provider.user_endpoint is not None headers = self.__get_default_headers() headers["Authorization"] = f"Bearer {self.__token.access_token}" - user_req = httpx.Request("GET", self.provider.user_endpoint, headers=headers) - async with httpx.AsyncClient(follow_redirects=True) as client: + user_req = httpx2.Request("GET", self.provider.user_endpoint, headers=headers) + async with httpx2.AsyncClient(follow_redirects=True) as client: user_resp = await client.send(user_req) user_resp.raise_for_status() assert self.provider.user_id_fn is not None diff --git a/sdk/python/packages/flet/src/flet/auth/providers/github_oauth_provider.py b/sdk/python/packages/flet/src/flet/auth/providers/github_oauth_provider.py index 6921f48fce..6f55b5b64e 100644 --- a/sdk/python/packages/flet/src/flet/auth/providers/github_oauth_provider.py +++ b/sdk/python/packages/flet/src/flet/auth/providers/github_oauth_provider.py @@ -38,14 +38,11 @@ async def _fetch_groups(self, access_token: str) -> list[Group]: Returns: A list of :class:`~flet.auth.Group` mapped from `/user/teams`. """ - try: - import httpx2 as httpx - except ImportError: - import httpx + import httpx2 - async with httpx.AsyncClient(follow_redirects=True) as client: + async with httpx2.AsyncClient(follow_redirects=True) as client: teams_resp = await client.send( - httpx.Request( + httpx2.Request( "GET", "https://api.github.com/user/teams", headers=self.__get_client_headers(access_token), @@ -74,14 +71,11 @@ async def _fetch_user(self, access_token: str) -> Optional[User]: A :class:`~flet.auth.User` built from `/user`; its `email` is populated from the primary address in `/user/emails` when available. """ - try: - import httpx2 as httpx - except ImportError: - import httpx + import httpx2 - async with httpx.AsyncClient(follow_redirects=True) as client: + async with httpx2.AsyncClient(follow_redirects=True) as client: user_resp = await client.send( - httpx.Request( + httpx2.Request( "GET", "https://api.github.com/user", headers=self.__get_client_headers(access_token), @@ -91,7 +85,7 @@ async def _fetch_user(self, access_token: str) -> Optional[User]: uj = json.loads(user_resp.text) emails_resp = await client.send( - httpx.Request( + httpx2.Request( "GET", "https://api.github.com/user/emails", headers=self.__get_client_headers(access_token), From aa35d2f024390dcf23fdf586db5d26838d79cb35 Mon Sep 17 00:00:00 2001 From: xic Date: Wed, 9 Sep 2026 15:03:36 +0800 Subject: [PATCH 6/6] fix(sdk): declare certifi as an explicit dependency The packaged-app bootstrap (templates/build/*/lib/python.dart) imports certifi unconditionally to set REQUESTS_CA_BUNDLE/SSL_CERT_FILE and the Android default HTTPS context. It previously arrived transitively via httpx; httpx2 no longer depends on it, so a minimal packaged app would fail at startup with ModuleNotFoundError. Add it explicitly with the same Emscripten exclusion (the bootstrap never runs under Pyodide). Refs: #6809 --- sdk/python/packages/flet/pyproject.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sdk/python/packages/flet/pyproject.toml b/sdk/python/packages/flet/pyproject.toml index e74c756161..2d0cf39474 100644 --- a/sdk/python/packages/flet/pyproject.toml +++ b/sdk/python/packages/flet/pyproject.toml @@ -11,6 +11,10 @@ dependencies = [ "flet-web; extra == 'web'", "oauthlib >=3.2.2; platform_system != 'Emscripten'", "httpx2 >=2.12.0; platform_system != 'Emscripten'", + # Required by the packaged-app bootstrap (templates/build/*/lib/python.dart), + # which imports certifi unconditionally to configure the CA bundle. It used + # to arrive transitively via httpx; httpx2 no longer depends on it. + "certifi >=2024.2.2; platform_system != 'Emscripten'", "repath >=0.9.0", "msgpack >=1.1.0", "typing-extensions; python_version < '3.11'"