gh-128540: lookup default webbrowser on macOS (#130535)
Ensure web browser is launched by `webbrowser.open` on macOS, even for `file://` URLs.
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
import io
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import shlex
|
import shlex
|
||||||
@@ -5,6 +6,7 @@ import subprocess
|
|||||||
import sys
|
import sys
|
||||||
import unittest
|
import unittest
|
||||||
import webbrowser
|
import webbrowser
|
||||||
|
from functools import partial
|
||||||
from test import support
|
from test import support
|
||||||
from test.support import import_helper
|
from test.support import import_helper
|
||||||
from test.support import is_apple_mobile
|
from test.support import is_apple_mobile
|
||||||
@@ -301,6 +303,69 @@ class IOSBrowserTest(unittest.TestCase):
|
|||||||
self._test('open_new_tab')
|
self._test('open_new_tab')
|
||||||
|
|
||||||
|
|
||||||
|
class MockPopenPipe:
|
||||||
|
def __init__(self, cmd, mode):
|
||||||
|
self.cmd = cmd
|
||||||
|
self.mode = mode
|
||||||
|
self.pipe = io.StringIO()
|
||||||
|
self._closed = False
|
||||||
|
|
||||||
|
def write(self, buf):
|
||||||
|
self.pipe.write(buf)
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
self._closed = True
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
@unittest.skipUnless(sys.platform == "darwin", "macOS specific test")
|
||||||
|
@requires_subprocess()
|
||||||
|
class MacOSXOSAScriptTest(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
support.patch(self, os, "popen", self.mock_popen)
|
||||||
|
self.browser = webbrowser.MacOSXOSAScript("default")
|
||||||
|
|
||||||
|
def mock_popen(self, cmd, mode):
|
||||||
|
self.popen_pipe = MockPopenPipe(cmd, mode)
|
||||||
|
return self.popen_pipe
|
||||||
|
|
||||||
|
def test_default(self):
|
||||||
|
browser = webbrowser.get()
|
||||||
|
assert isinstance(browser, webbrowser.MacOSXOSAScript)
|
||||||
|
self.assertEqual(browser.name, "default")
|
||||||
|
|
||||||
|
def test_default_open(self):
|
||||||
|
url = "https://python.org"
|
||||||
|
self.browser.open(url)
|
||||||
|
self.assertTrue(self.popen_pipe._closed)
|
||||||
|
self.assertEqual(self.popen_pipe.cmd, "osascript")
|
||||||
|
script = self.popen_pipe.pipe.getvalue()
|
||||||
|
self.assertEqual(script.strip(), f'open location "{url}"')
|
||||||
|
|
||||||
|
def test_url_quote(self):
|
||||||
|
self.browser.open('https://python.org/"quote"')
|
||||||
|
script = self.popen_pipe.pipe.getvalue()
|
||||||
|
self.assertEqual(
|
||||||
|
script.strip(), 'open location "https://python.org/%22quote%22"'
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_default_browser_lookup(self):
|
||||||
|
url = "file:///tmp/some-file.html"
|
||||||
|
self.browser.open(url)
|
||||||
|
script = self.popen_pipe.pipe.getvalue()
|
||||||
|
# doesn't actually test the browser lookup works,
|
||||||
|
# just that the branch is taken
|
||||||
|
self.assertIn("URLForApplicationToOpenURL", script)
|
||||||
|
self.assertIn(f'open location "{url}"', script)
|
||||||
|
|
||||||
|
def test_explicit_browser(self):
|
||||||
|
browser = webbrowser.MacOSXOSAScript("safari")
|
||||||
|
browser.open("https://python.org")
|
||||||
|
script = self.popen_pipe.pipe.getvalue()
|
||||||
|
self.assertIn('tell application "safari"', script)
|
||||||
|
self.assertIn('open location "https://python.org"', script)
|
||||||
|
|
||||||
|
|
||||||
class BrowserRegistrationTest(unittest.TestCase):
|
class BrowserRegistrationTest(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
|||||||
@@ -597,7 +597,32 @@ if sys.platform == 'darwin':
|
|||||||
sys.audit("webbrowser.open", url)
|
sys.audit("webbrowser.open", url)
|
||||||
url = url.replace('"', '%22')
|
url = url.replace('"', '%22')
|
||||||
if self.name == 'default':
|
if self.name == 'default':
|
||||||
script = f'open location "{url}"' # opens in default browser
|
proto, _sep, _rest = url.partition(":")
|
||||||
|
if _sep and proto.lower() in {"http", "https"}:
|
||||||
|
# default web URL, don't need to lookup browser
|
||||||
|
script = f'open location "{url}"'
|
||||||
|
else:
|
||||||
|
# if not a web URL, need to lookup default browser to ensure a browser is launched
|
||||||
|
# this should always work, but is overkill to lookup http handler
|
||||||
|
# before launching http
|
||||||
|
script = f"""
|
||||||
|
use framework "AppKit"
|
||||||
|
use AppleScript version "2.4"
|
||||||
|
use scripting additions
|
||||||
|
|
||||||
|
property NSWorkspace : a reference to current application's NSWorkspace
|
||||||
|
property NSURL : a reference to current application's NSURL
|
||||||
|
|
||||||
|
set http_url to NSURL's URLWithString:"https://python.org"
|
||||||
|
set browser_url to (NSWorkspace's sharedWorkspace)'s ¬
|
||||||
|
URLForApplicationToOpenURL:http_url
|
||||||
|
set app_path to browser_url's relativePath as text -- NSURL to absolute path '/Applications/Safari.app'
|
||||||
|
|
||||||
|
tell application app_path
|
||||||
|
activate
|
||||||
|
open location "{url}"
|
||||||
|
end tell
|
||||||
|
"""
|
||||||
else:
|
else:
|
||||||
script = f'''
|
script = f'''
|
||||||
tell application "{self.name}"
|
tell application "{self.name}"
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
Ensure web browser is launched by :func:`webbrowser.open` on macOS, even for
|
||||||
|
``file://`` URLs.
|
||||||
Reference in New Issue
Block a user