webview import fixes

This commit is contained in:
Jakob Pinterits
2024-11-07 23:01:48 +01:00
parent 6e30b4f294
commit 11ebc24d70
11 changed files with 51 additions and 81 deletions

View File

@@ -679,7 +679,7 @@ class App:
Error messages will be printed regardless of this setting.
"""
try:
from .webview import webview
from . import webview_shim
except ImportError:
raise Exception(
"The `window` extra is required to use `App.run_in_window`."
@@ -723,7 +723,7 @@ class App:
# Problem: width and height are given in rem, but we need them in
# pixels. We'll use pywebview's execute_js to find out as soon as the
# window has been created, and then update the window size accordingly.
def update_window_size():
def update_window_size() -> None:
if width is None and height is None:
return
@@ -753,13 +753,13 @@ pixels_per_rem
# Start the webview
try:
window = webview.create_window(
window = webview_shim.create_window(
self.name,
url,
maximized=maximized,
fullscreen=fullscreen,
)
webview.start(
webview_shim.start(
update_window_size,
debug=os.environ.get("RIO_WEBVIEW_DEBUG") == "1",
)

View File

@@ -70,7 +70,7 @@ class HttpResponse:
def _request_sync(
method: t.Literal["GET", "POST"],
method: t.Literal["get", "post"],
url: str,
*,
content: str | bytes | None = None,
@@ -134,7 +134,7 @@ def _request_sync(
async def request(
method: t.Literal["GET", "POST"],
method: t.Literal["get", "post"],
url: str,
*,
content: bytes | None = None,
@@ -158,7 +158,7 @@ async def request(
async def main() -> None:
response = await request(
"GET",
"get",
"https://postman-echo.com/get?foo=bar",
)

View File

@@ -257,7 +257,7 @@ class UrlAsset(Asset):
async def try_fetch_as_blob(self) -> tuple[bytes, str | None]:
try:
response = await arequests.request("GET", str(self._url))
response = await arequests.request("get", str(self._url))
content_type = response.headers.get("content-type")

View File

@@ -62,7 +62,7 @@ class RioApi:
self,
endpoint: str,
*,
method: t.Literal["get", "post", "delete"] = "get",
method: t.Literal["get", "post"] = "get",
json: dict[str, t.Any] | None = None,
file: t.BinaryIO | None = None,
) -> t.Any:
@@ -87,7 +87,7 @@ class RioApi:
f"{BASE_URL}/{endpoint}",
headers=headers,
json=json,
files=files,
# files=files, # TODO:
)
# Handle errors

View File

@@ -29,15 +29,6 @@ from . import (
webview_worker,
)
try:
from ...webview import webview
except ImportError:
if t.TYPE_CHECKING:
from ...webview import webview
else:
webview = None
# There is a hilarious problem with `watchfiles`: When a change occurs,
# `watchfiles` logs that change. If Python is configured to log into the project
# directory, then `watchfiles` will pick up on that new log line, thus
@@ -188,7 +179,7 @@ class Arbiter:
"""
try:
response = await arequests.request(
"GET",
"get",
"https://pypi.org/pypi/rio-ui/json",
)
@@ -429,11 +420,13 @@ class Arbiter:
self._arbiter_task = asyncio.current_task()
# Make sure the webview module is available
if self.run_in_window and webview is None:
revel.fatal(
"The `window` extra is required to run apps inside of a window."
""" Run `pip install "rio-ui[[window]"` to install it."""
)
if self.run_in_window:
try:
from ... import webview_shim as webview_shim
except ImportError:
revel.fatal(
"""The `window` extra is required to run apps inside of a window. Run `pip install "rio-ui[[window]"` to install it."""
)
# Make sure the app is cleanly shut down, even if the arbiter crashes
# for whichever reason.

View File

@@ -4,14 +4,6 @@ import typing as t
from . import run_models
try:
from ...webview import webview
except ImportError:
if t.TYPE_CHECKING:
from ...webview import webview
else:
webview = None
class WebViewWorker:
def __init__(
@@ -21,12 +13,14 @@ class WebViewWorker:
debug_mode: bool,
url: str,
) -> None:
from ... import webview_shim
self.push_event = push_event
self.debug_mode = debug_mode
self.url = url
# If running, this is the webview window
self.window: webview.Window | None = None
self.window: webview_shim.Window | None = None
def run(self) -> None:
"""
@@ -34,7 +28,8 @@ class WebViewWorker:
`request_stop` is called. This function must be called from the main
thread.
"""
assert webview is not None
from ... import webview_shim
assert self.window is None, "Already running"
# Make sure this was called from the main thread.
@@ -43,12 +38,12 @@ class WebViewWorker:
), "Must be called from the main thread"
# Create the window
self.window = webview.create_window(
self.window = webview_shim.create_window(
# TODO: Get the app's name, if possible
"Rio (debug)" if self.debug_mode else "Rio",
url=self.url,
)
webview.start()
webview_shim.start()
# If we've reached this point, the window must have been closed.
self.window = None

View File

@@ -18,13 +18,6 @@ __all__ = [
T = t.TypeVar("T")
class NotGiven:
pass
NOT_GIVEN = NotGiven()
@t.final
@rio.docs.mark_constructor_as_private
@dataclass
@@ -135,7 +128,7 @@ class Dropdown(FundamentalComponent, t.Generic[T]):
_: KW_ONLY
label: str
style: t.Literal["underlined", "rounded", "pill"]
selected_value: T | utils.NotGiven = NOT_GIVEN
selected_value: T | utils.NotGiven = utils.NOT_GIVEN
is_sensitive: bool
is_valid: bool
on_change: rio.EventHandler[DropdownChangeEvent[T]]

View File

@@ -851,7 +851,7 @@ class Layouter:
round(self.window_width * pixels_per_unit),
round(self.window_height * pixels_per_unit),
),
color="white",
color="white", # type: ignore
)
draw = PIL.ImageDraw.Draw(image)

View File

@@ -637,11 +637,11 @@ window.resizeTo(screen.availWidth, screen.availHeight);
# Close the tab / window
if close_remote_session:
if self.running_in_window:
from .webview import webview
from . import webview_shim
# It's possible that the session is being closed because the
# user closed the window, so the window may not exist anymore
window = webview.active_window()
window = webview_shim.active_window()
if window is not None:
window.destroy()
else:
@@ -674,7 +674,7 @@ window.resizeTo(screen.availWidth, screen.availHeight);
return low_level_root.content
async def _get_webview_window(self):
from .webview import webview
from . import webview_shim
assert (
self.running_in_window
@@ -682,7 +682,7 @@ window.resizeTo(screen.availWidth, screen.availHeight);
# The window may not have opened yet, so we'll wait until it exists
while True:
window = webview.active_window()
window = webview_shim.active_window()
if window is not None:
return window
@@ -2023,9 +2023,7 @@ window.history.{method}(null, "", {json.dumps(str(active_page_url.relative()))})
`title`: The new window title.
"""
if self.running_in_window:
import webview.util # type: ignore
from .webview import webview
from . import webview_shim
window = await self._get_webview_window()
@@ -2033,7 +2031,7 @@ window.history.{method}(null, "", {json.dumps(str(active_page_url.relative()))})
try:
window.set_title(title)
break
except webview.util.WebViewException:
except webview_shim.util.WebViewException:
await asyncio.sleep(0.2)
else:
await self._remote_set_title(title)
@@ -2184,11 +2182,11 @@ window.history.{method}(null, "", {json.dumps(str(active_page_url.relative()))})
# way to open a file dialog without blocking the event loop.
import aiofiles
from .webview import webview
from . import webview_shim
window = await self._get_webview_window()
destinations = window.create_file_dialog(
webview.SAVE_DIALOG,
webview_shim.SAVE_DIALOG,
directory="" if directory is None else str(directory),
save_filename=file_name,
)

View File

@@ -1,6 +1,5 @@
from __future__ import annotations
import asyncio
import hashlib
import mimetypes
import os
@@ -9,7 +8,6 @@ import secrets
import socket
import typing as t
from dataclasses import dataclass
from http.client import HTTPSConnection
from io import BytesIO, StringIO
from pathlib import Path
@@ -567,24 +565,3 @@ def soft_sort(
for element, _, _ in keyed_elements:
elements.append(element)
async def async_http_request(url: str) -> Tuple[Dict[str, str], bytes]:
"""Performs an async HTTP GET request to the given URL and returns headers and content blob."""
loop = asyncio.get_running_loop()
host, path = url.split("/", 1)
def fetch() -> Tuple[Dict[str, str], bytes]:
conn = HTTPSConnection(host)
conn.request("GET", f"/{path}")
response = conn.getresponse()
headers = dict(response.getheaders())
blob = response.read()
conn.close()
return headers, blob
return await loop.run_in_executor(None, fetch)
# Example usage:
# headers, blob = asyncio.run(async_http_request("example.com/some-path"))

View File

@@ -1,4 +1,11 @@
__all__ = ["webview"]
__all__ = [
"active_window",
"create_window",
"SAVE_DIALOG",
"start",
"util",
"Window",
]
# There is an issue with `rye test`. rye passes a `--rootdir` argument to
@@ -11,7 +18,14 @@ argv = sys.argv
sys.argv = argv[:1]
try:
import webview
from webview import (
SAVE_DIALOG,
Window,
active_window,
create_window,
start,
util,
)
except ImportError:
pass
finally: