Transferring from GitHub as suggested by @nad for discussion of a possible implementation.
Summary
Often, webbrowser.open
will use a platform’s “default opener” such as open
on mac, xdg-open
on linux, or os.startfile
on Windows. This works just fine for http[s] URLs, but when attempting to open file://
URLs, all of these mechanisms launch the default application by file-type, which is often not a browser.
As such, file://
URLs are effectively unsupported by webbrowser.open
in many cases. though notably they do work reliably if $BROWSER
is set to an actual browser executable.
There are APIs to lookup default browsers, but webbrowser.py does not use them (except sometimes on Linux, more below). It would be nice if webbrowser.open("file:///path/to/some.html")
worked more often.
Proposal
I would like to introduce official support for file://
URLs by explicitly looking up the default browser and launching it, rather than using these indirect methods, which don’t handle file://
URLs consistently. Looking up default browsers is not always easy, but there are some standard APIs. This could be done always, or only for file://
URLs to limit the impact.
Prototype
I’ve written a prototype to test implementations. It uses the following per-platform APIs:
macOS
- lookup default browser Application with URLForApplicationToOpenURL via ctypes. This is almost identical to the existing ios implementation in webbrowser.py.
- launch it with applescript, just like existing applications
alternative: fully ctypes implementation, using openURLs:withApplication...
. This would be even more similar to the existing ios implementation (maybe they could even be merged?)
Windows
- Lookup default browser via
winreg
...\UrlAssociations\https\UserChoice
- Lookup command-line via
$progId\shell\open\command
- replace Windows
%1
with the%s
webbrowser.py expects - create a GenericBrowser with that command-line
(I have no idea how/when looking up these registry keys may fail on different Windows situations)
Linux / XDG
This one seems the hardest, since there are so many different situations to handle. But from my tests, I’ve found these ways to lookup the default browser:
xdg-settings get default-web-browser
# or
xdg-mime query default x-scheme-handler/https
which returns e.g. firefox_firefox.desktop
by default in a fresh Ubuntu install.
(notably, webbrowser.py does call xdg-settings get default-webbrowser
, but this only sets the default browser if it is a strict match to a hardcoded list, which doesn’t include a default snap install of Firefox on Ubuntu because it is firefox_firefox.desktop
not firefox.desktop
).
Once the default browser is found, launch with either gtk-launch
(preferred, since it searches $XDG_DATA paths), or gio launch
(after searching $XDG_DATA, since gio launch
seems to require absolute paths to .desktop files).
I have no idea how many other ways there are to lookup or launch ‘default’ browsers on various flavors of linux and other OSes.
alternative
since default-openers are known to not work for file://
URLs, they could explicitly not support them (return False
from open), which would mean falling back on later choices that reference browsers explicitly. This would mean the default browser choice would not be respected (in the cases where it already isn’t), but at least a browser would be launched reliably instead of the default application, which may not be a browser at all.