8000 gh-128540: lookup default webbrowser on macOS (#130535) · python/cpython@9649278 · GitHub
[go: up one dir, main page]

Skip to content

Commit 9649278

Browse files
authored
gh-128540: lookup default webbrowser on macOS (#130535)
Ensure web browser is launched by `webbrowser.open` on macOS, even for `file://` URLs.
1 parent f3e275f commit 9649278

File tree

3 files changed

+93
-1
lines changed

3 files changed

+93
-1
lines changed

Lib/test/test_webbrowser.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1+
import io
12
import os
23
import re
34
import shlex
45
import subprocess
56
import sys
67
import unittest
78
import webbrowser
9+
from functools import partial
810
from test import support
911
from test.support import import_helper
1012
from test.support import is_apple_mobile
@@ -301,6 +303,69 @@ def test_open_new_tab(self):
301303
self._test('open_new_tab')
302304

303305

306+
class MockPopenPipe:
307+
def __init__(self, cmd, mode):
308+
self.cmd = cmd
309+
self.mode = mode
310+
self.pipe = io.StringIO()
311+
self._closed = False
312+
313+
def write(self, buf):
314+
self.pipe.write(buf)
315+
316+
def close(self):
317+
self._closed = True
318+
return None
319+
320+
321+
@unittest.skipUnless(sys.platform == "darwin", "macOS specific test")
322+
@requires_subprocess()
323+
class MacOSXOSAScriptTest(unittest.TestCase):
324+
def setUp(self):
325+
support.patch(self, os, "popen", self.mock_popen)
326+
self.browser = webbrowser.MacOSXOSAScript("default")
327+
328+
def mock_popen(self, cmd, mode):
329+
self.popen_pipe = MockPopenPipe(cmd, mode)
330+
return self.popen_pipe
331+
332+
def test_default(self):
333+
browser = webbrowser.get()
334+
assert isinstance(browser, webbrowser.MacOSXOSAScript)
335+
self.assertEqual(browser.name, "default")
336+
337+
def test_default_open(self):
338+
url = "https://python.org"
339+
self.browser.open(url)
340+
self.assertTrue(self.popen_pipe._closed)
341+
self.assertEqual(self.popen_pipe.cmd, "osascript")
342+
script = self.popen_pipe.pipe.getvalue()
343+
self.assertEqual(script.strip(), f'open location "{url}"')
344+
345+
def test_url_quote(self):
346+
self.browser.open('https://python.org/"quote"')
347+
script = self.popen_pipe.pipe.getvalue()
348+
self.assertEqual(
349+
script.strip(), 'open location "https://python.org/%22quote%22"'
350+
)
351+
352+
def test_default_browser_lookup(self):
353+
url = "file:///tmp/some-file.html"
354+
self.browser.open(url)
355+
script = self.popen_pipe.pipe.getvalue()
356+
# doesn't actually test the browser lookup works,
357+
# just that the branch is taken
358+
self.assertIn("URLForApplicationToOpenURL", script)
359+
self.assertIn(f'open location "{url}"', script)
360+
361+
def test_explicit_browser(self):
362+
browser = webbrowser.MacOSXOSAScript("safari")
363+
browser.open("https://python.org")
364+
script = self.popen_pipe.pipe.getvalue()
365+
self.assertIn('tell application "safari"', script)
366+
self.assertIn('open location "https://python.org"', script)
367+
368+
304369
class BrowserRegistrationTest(unittest.TestCase):
305370

306371
def setUp(self):

Lib/webbrowser.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -597,7 +597,32 @@ def open(self, url, new=0, autoraise=True):
597597
sys.audit("webbrowser.open", url)
598598
url = url.replace('"', '%22')
599599
if self.name == 'default':
600-
script = f'open location "{url}"' # opens in default browser
600+
proto, _sep, _rest = url.partition(":")
601+
if _sep and proto.lower() in {"http", "https"}:
602+
# default web URL, don't need to lookup browser
603+
script = f'open location "{url}"'
604+
else:
605+
# if not a web URL, need to lookup default browser to ensure a browser is launched
606+
# this should always work, but is overkill to lookup http handler
607+
# before launching http
608+
script = f"""
609+
use framework "AppKit"
610+
use AppleScript version "2.4"
611+
use scripting additions
612+
613+
property NSWorkspace : a reference to current application's NSWorkspace
614+
property NSURL : a reference to current application's NSURL
615+
616+
set http_url to NSURL's URLWithString:"https://python.org"
617+
set browser_url to (NSWorkspace's sharedWorkspace)'s ¬
618+
URLForApplicationToOpenURL:http_url
619+
set app_path to browser_url's relativePath as text -- NSURL to absolute path '/Applications/Safari.app'
620+
621+
tell application app_path
622+
activate
623+
open location "{url}"
624+
end tell
625+
"""
601626
else:
602627
script = f'''
603628
tell application "{self.name}"
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Ensure web browser is launched by :func:`webbrowser.open` on macOS, even for
2+
``file://`` URLs.

0 commit comments

Comments
 (0)
0