Changelog
0.4.0
A deliberately breaking release. Every break is covered, with what to do about it, in the migration guide.
Breaking
- Python 3.14 is the floor. Wheels are stable-ABI (
abi3-py314), one per platform; 3.11–3.13 are no longer supported, and free-threaded builds cannot install Dry untilabi3t. - The JavaScript surface is namespaced under
window.dry.window.api,window.minimize,window.toggleMaximize,window.close,window.dragandwindow.resizemove under it;window.ipcCallbackandwindow.ipcStoreare gone from the public surface.window.close,window.resizeToandwindow.resizeByare the browser’s own again. - Content is explicit.
wv.contentand its sniffing are replaced by three mutually exclusive modes:html,urlandroot. Declaring two raises; declaring none raises atrun(). There is no single-file mode and no built-in placeholder page. Webview(...)takes keyword arguments, and assigning an unknown attribute raises. Settings read while the window is built raise if assigned afterrun(), naming the setting.- An App id decides where data lives, replacing a folder derived from the
window title under the temporary directory. Cookies, local storage and cache
move to the OS application-data directory, and existing sessions do not carry
over.
titleis now cosmetic. - The Bridge contract is the JSON data model, in both directions.
set,frozenset,bytesandbytearrayraise; integers beyond ±2**53,NaNandInfinityraise; booleans arrive as booleans rather than as1and0; dictionary keys are coerced to strings asjson.dumpscoerces them. sizeandmin_sizeare logical pixels, so a window on a scaled display opens at the size it declares rather than at that size divided by the scale factor.- A drag region drags its whole subtree. Interactive elements inside one
need
data-no-drag-region. - Failures are exceptions and log records.
DryError,WebviewError,BridgeErrorandPanicErrorreplace printed diagnostics and an aborting panic; Dry writes nothing to stdout or stderr, logging instead todry,dry.webviewanddry.bridge. - Api entries must be callable, checked before the window opens, and a Call’s arguments are checked against the callable’s declared annotations before it runs.
- Callbacks run off the window’s thread and concurrently, so state shared between them must be thread-safe.
Added
- Events in both directions:
wv.on,wv.off,wv.emitandwv.eval_jsin Python;window.dry.on,offandemitin the frontend. - Window Events under reserved
window:names —maximized,unmaximized,minimized,restored,hidden,shown,focused,blurred,resized,moved,close-requested— delivered on the same bus to both sides, and fired for OS-initiated changes as much as for library-initiated ones. - Runtime window control.
title,size,min_size,decorationsandicon_pathnow apply to the open window instead of only changing a stored value, andposition,visible,maximized,minimizedandfullscreenjoin them as properties of a window on screen, raising aRuntimeErrornaming the property beforerun(). Every change is announced through the window Events exactly as a change the user made. - A state query on both sides:
wv.state()returns aWindowStateNamedTuple, andawait window.dry.state()resolves the same reading in the frontend, for a listener or a page that has observed no change yet. - A Root: a local directory served over an internal protocol so relative
assets resolve, with per-extension content types,
index.htmlfor directories,403for a path escaping the Root and404for a missing file. - A close hook:
on_close, asked on every route in, able to refuse a close by returningFalse, followed by an ordered shutdown that drains in-flight Calls and runsatexithandlers. - A
default=hook, the onejson.dumps(default=...)takes, for converting your own types on the way out. data-no-drag-region, opting an element and its subtree out of a drag region.- macOS support, built and tested in CI alongside Windows, including resize edges on an undecorated window, which tao does not support natively.
- A documentation site, and a README that is a README again.
Fixed
run()no longer holds the GIL, so Python threads keep running for the life of the window. A local server in athreading.Threadworks.- A failed navigation is diagnosed and reported on
dry.webviewinstead of leaving a blank window with no explanation. - A
localfile://request no longer ignores its path and answers with a content type that is not a media type. - A window declared 800×600 opens at that apparent size on a display of any scale factor.
Known gaps
- The window-size fix above was verified on macOS across a real scale change,
dragging between displays at
backingScaleFactor2.0 and 1.0. The scenario originally reported — Windows at 100% and 150% — has not been reproduced, because a CI runner has a single display at 100% where logical and physical pixels are indistinguishable. Reports from Windows are welcome. - On macOS, resize edges are drawn by Dry rather than the platform, because
tao’s
drag_resize_windowis unimplemented there. A window built decorated and undecorated at runtime never draws them.
Releases before 0.4.0 predate this changelog. Their history is in the commit log.