mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-02 19:39:49 +09:00
Update webbrowser.py to 3.14.5 (#7868)
This commit is contained in:
94
Lib/test/test_webbrowser.py
vendored
94
Lib/test/test_webbrowser.py
vendored
@@ -1,3 +1,4 @@
|
||||
import io
|
||||
import os
|
||||
import re
|
||||
import shlex
|
||||
@@ -5,6 +6,7 @@ import subprocess
|
||||
import sys
|
||||
import unittest
|
||||
import webbrowser
|
||||
from functools import partial
|
||||
from test import support
|
||||
from test.support import import_helper
|
||||
from test.support import is_apple_mobile
|
||||
@@ -55,6 +57,14 @@ class CommandTestMixin:
|
||||
popen_args.pop(popen_args.index(option))
|
||||
self.assertEqual(popen_args, arguments)
|
||||
|
||||
def test_reject_dash_prefixes(self):
|
||||
browser = self.browser_class(name=CMD_NAME)
|
||||
with self.assertRaisesRegex(
|
||||
ValueError,
|
||||
r"^Invalid URL \(leading dash disallowed\): '--key=val http.*'$"
|
||||
):
|
||||
browser.open(f"--key=val {URL}")
|
||||
|
||||
|
||||
class GenericBrowserCommandTest(CommandTestMixin, unittest.TestCase):
|
||||
|
||||
@@ -109,6 +119,15 @@ class ChromeCommandTest(CommandTestMixin, unittest.TestCase):
|
||||
arguments=[URL],
|
||||
kw=dict(new=999))
|
||||
|
||||
def test_reject_action_dash_prefixes(self):
|
||||
browser = self.browser_class(name=CMD_NAME)
|
||||
with self.assertRaises(ValueError):
|
||||
browser.open('%action--incognito')
|
||||
# new=1: action is "--new-window", so "%action" itself expands to
|
||||
# a dash-prefixed flag even with no dash in the original URL.
|
||||
with self.assertRaises(ValueError):
|
||||
browser.open('%action', new=1)
|
||||
|
||||
|
||||
class EdgeCommandTest(CommandTestMixin, unittest.TestCase):
|
||||
|
||||
@@ -301,6 +320,81 @@ class IOSBrowserTest(unittest.TestCase):
|
||||
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):
|
||||
# Ensure that 'BROWSER' is not set to 'open' or something else.
|
||||
# See: https://github.com/python/cpython/issues/131254.
|
||||
env = self.enterContext(os_helper.EnvironmentVarGuard())
|
||||
env.unset("BROWSER")
|
||||
|
||||
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, "/usr/bin/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)
|
||||
|
||||
def test_reject_dash_prefixes(self):
|
||||
with self.assertRaisesRegex(
|
||||
ValueError,
|
||||
r"^Invalid URL \(leading dash disallowed\): '--key=val http.*'$"
|
||||
):
|
||||
self.browser.open(f"--key=val {URL}")
|
||||
|
||||
|
||||
class BrowserRegistrationTest(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
|
||||
67
Lib/webbrowser.py
vendored
Executable file → Normal file
67
Lib/webbrowser.py
vendored
Executable file → Normal file
@@ -1,4 +1,3 @@
|
||||
#! /usr/bin/env python3
|
||||
"""Interfaces for launching and remotely controlling web browsers."""
|
||||
# Maintained by Georg Brandl.
|
||||
|
||||
@@ -164,6 +163,12 @@ class BaseBrowser:
|
||||
def open_new_tab(self, url):
|
||||
return self.open(url, 2)
|
||||
|
||||
@staticmethod
|
||||
def _check_url(url):
|
||||
"""Ensures that the URL is safe to pass to subprocesses as a parameter"""
|
||||
if url and url.lstrip().startswith("-"):
|
||||
raise ValueError(f"Invalid URL (leading dash disallowed): {url!r}")
|
||||
|
||||
|
||||
class GenericBrowser(BaseBrowser):
|
||||
"""Class for all browsers started with a command
|
||||
@@ -181,6 +186,7 @@ class GenericBrowser(BaseBrowser):
|
||||
|
||||
def open(self, url, new=0, autoraise=True):
|
||||
sys.audit("webbrowser.open", url)
|
||||
self._check_url(url)
|
||||
cmdline = [self.name] + [arg.replace("%s", url)
|
||||
for arg in self.args]
|
||||
try:
|
||||
@@ -201,6 +207,7 @@ class BackgroundBrowser(GenericBrowser):
|
||||
cmdline = [self.name] + [arg.replace("%s", url)
|
||||
for arg in self.args]
|
||||
sys.audit("webbrowser.open", url)
|
||||
self._check_url(url)
|
||||
try:
|
||||
if sys.platform[:3] == 'win':
|
||||
p = subprocess.Popen(cmdline)
|
||||
@@ -280,7 +287,9 @@ class UnixBrowser(BaseBrowser):
|
||||
raise Error("Bad 'new' parameter to open(); "
|
||||
f"expected 0, 1, or 2, got {new}")
|
||||
|
||||
args = [arg.replace("%s", url).replace("%action", action)
|
||||
self._check_url(url.replace("%action", action))
|
||||
|
||||
args = [arg.replace("%action", action).replace("%s", url)
|
||||
for arg in self.remote_args]
|
||||
args = [arg for arg in args if arg]
|
||||
success = self._invoke(args, True, autoraise, url)
|
||||
@@ -358,6 +367,7 @@ class Konqueror(BaseBrowser):
|
||||
|
||||
def open(self, url, new=0, autoraise=True):
|
||||
sys.audit("webbrowser.open", url)
|
||||
self._check_url(url)
|
||||
# XXX Currently I know no way to prevent KFM from opening a new win.
|
||||
if new == 2:
|
||||
action = "newTab"
|
||||
@@ -483,10 +493,10 @@ def register_standard_browsers():
|
||||
|
||||
if sys.platform == 'darwin':
|
||||
register("MacOSX", None, MacOSXOSAScript('default'))
|
||||
register("chrome", None, MacOSXOSAScript('chrome'))
|
||||
register("chrome", None, MacOSXOSAScript('google chrome'))
|
||||
register("firefox", None, MacOSXOSAScript('firefox'))
|
||||
register("safari", None, MacOSXOSAScript('safari'))
|
||||
# OS X can use below Unix support (but we prefer using the OS X
|
||||
# macOS can use below Unix support (but we prefer using the macOS
|
||||
# specific stuff)
|
||||
|
||||
if sys.platform == "ios":
|
||||
@@ -560,6 +570,19 @@ def register_standard_browsers():
|
||||
# Treat choices in same way as if passed into get() but do register
|
||||
# and prepend to _tryorder
|
||||
for cmdline in userchoices:
|
||||
if all(x not in cmdline for x in " \t"):
|
||||
# Assume this is the name of a registered command, use
|
||||
# that unless it is a GenericBrowser.
|
||||
try:
|
||||
command = _browsers[cmdline.lower()]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
else:
|
||||
if not isinstance(command[1], GenericBrowser):
|
||||
_tryorder.insert(0, cmdline.lower())
|
||||
continue
|
||||
|
||||
if cmdline != '':
|
||||
cmd = _synthesize(cmdline, preferred=True)
|
||||
if cmd[1] is None:
|
||||
@@ -576,6 +599,7 @@ if sys.platform[:3] == "win":
|
||||
class WindowsDefault(BaseBrowser):
|
||||
def open(self, url, new=0, autoraise=True):
|
||||
sys.audit("webbrowser.open", url)
|
||||
self._check_url(url)
|
||||
try:
|
||||
os.startfile(url)
|
||||
except OSError:
|
||||
@@ -596,9 +620,35 @@ if sys.platform == 'darwin':
|
||||
|
||||
def open(self, url, new=0, autoraise=True):
|
||||
sys.audit("webbrowser.open", url)
|
||||
self._check_url(url)
|
||||
url = url.replace('"', '%22')
|
||||
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:
|
||||
script = f'''
|
||||
tell application "{self.name}"
|
||||
@@ -607,7 +657,7 @@ if sys.platform == 'darwin':
|
||||
end
|
||||
'''
|
||||
|
||||
osapipe = os.popen("osascript", "w")
|
||||
osapipe = os.popen("/usr/bin/osascript", "w")
|
||||
if osapipe is None:
|
||||
return False
|
||||
|
||||
@@ -627,6 +677,7 @@ if sys.platform == "ios":
|
||||
class IOSBrowser(BaseBrowser):
|
||||
def open(self, url, new=0, autoraise=True):
|
||||
sys.audit("webbrowser.open", url)
|
||||
self._check_url(url)
|
||||
# If ctypes isn't available, we can't open a browser
|
||||
if objc is None:
|
||||
return False
|
||||
@@ -682,7 +733,9 @@ if sys.platform == "ios":
|
||||
|
||||
def parse_args(arg_list: list[str] | None):
|
||||
import argparse
|
||||
parser = argparse.ArgumentParser(description="Open URL in a web browser.")
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Open URL in a web browser.", color=True,
|
||||
)
|
||||
parser.add_argument("url", help="URL to open")
|
||||
|
||||
group = parser.add_mutually_exclusive_group()
|
||||
|
||||
Reference in New Issue
Block a user