diff -r a21ddb1c41d2 Lib/webbrowser.py
--- a/Lib/webbrowser.py Fri Aug 22 10:28:42 2014 -0400
+++ b/Lib/webbrowser.py Tue Aug 26 15:02:48 2014 +0200
@@ -10,12 +10,14 @@ import subprocess
__all__ = ["Error", "open", "open_new", "open_new_tab", "get", "register"]
+
class Error(Exception):
pass
_browsers = {} # Dictionary of available browser controllers
_tryorder = [] # Preference order of available browsers
+
def register(name, klass, instance=None, update_tryorder=1):
"""Register a browser connector and, optionally, connection."""
_browsers[name.lower()] = [klass, instance]
@@ -24,6 +26,7 @@ def register(name, klass, instance=None,
elif update_tryorder < 0:
_tryorder.insert(0, name)
+
def get(using=None):
"""Return a browser launcher instance appropriate for the environment."""
if using is not None:
@@ -54,18 +57,21 @@ def get(using=None):
# It is recommended one does "import webbrowser" and uses webbrowser.open(url)
# instead of "from webbrowser import *".
-def open(url, new=0, autoraise=True):
+
+def open(url, new=0, autoraise=True, stdout=True, stderr=True):
for name in _tryorder:
browser = get(name)
- if browser.open(url, new, autoraise):
+ if browser.open(url, new, autoraise, stdout, stderr):
return True
return False
-def open_new(url):
- return open(url, 1)
-def open_new_tab(url):
- return open(url, 2)
+def open_new(url, stdout=True, stderr=True):
+ return open(url, 1, stdout=stdout, stderr=stderr)
+
+
+def open_new_tab(url, stdout=True, stderr=True):
+ return open(url, 2, stdout=stdout, stderr=stderr)
def _synthesize(browser, update_tryorder=1):
@@ -100,6 +106,24 @@ def _synthesize(browser, update_tryorder
return [None, None]
+def _manage_fds(fds):
+ """Manage the file descriptors redirection:
+ * True -> None (subprocess inherits file descriptors from
+ the parent process)
+ * None or False -> /dev/null
+ * any other value follows subprocess documentation
+ """
+ # from subprocess module documentation:
+ # With the default settings of None, no redirection will occur;
+ # the child's file handles will be inherited from the parent.
+ if fds is True:
+ fds = None
+ elif fds is None or fds is False:
+ fds = subprocess.DEVNULL
+
+ return fds
+
+
# General parent classes
class BaseBrowser(object):
@@ -111,14 +135,14 @@ class BaseBrowser(object):
self.name = name
self.basename = name
- def open(self, url, new=0, autoraise=True):
+ def open(self, url, new=0, autoraise=True, stdout=True, stderr=True):
raise NotImplementedError
- def open_new(self, url):
- return self.open(url, 1)
+ def open_new(self, url, stdout=True, stderr=True):
+ return self.open(url, 1, stdout=stdout, stderr=stderr)
- def open_new_tab(self, url):
- return self.open(url, 2)
+ def open_new_tab(self, url, stdout=True, stderr=True):
+ return self.open(url, 2, stdout=stdout, stderr=stderr)
class GenericBrowser(BaseBrowser):
@@ -135,14 +159,28 @@ class GenericBrowser(BaseBrowser):
self.args = name[1:]
self.basename = os.path.basename(self.name)
- def open(self, url, new=0, autoraise=True):
+ def open(self,
+ url,
+ new=0,
+ autoraise=True,
+ stdout=True,
+ stderr=True
+ ):
cmdline = [self.name] + [arg.replace("%s", url)
for arg in self.args]
+
+ redirect_stdout = _manage_fds(stdout)
+ redirect_stderr = _manage_fds(stderr)
+
try:
if sys.platform[:3] == 'win':
p = subprocess.Popen(cmdline)
else:
- p = subprocess.Popen(cmdline, close_fds=True)
+ p = subprocess.Popen(cmdline,
+ close_fds=True,
+ stdout=redirect_stdout,
+ stderr=redirect_stderr
+ )
return not p.wait()
except OSError:
return False
@@ -152,9 +190,19 @@ class BackgroundBrowser(GenericBrowser):
"""Class for all browsers which are to be started in the
background."""
- def open(self, url, new=0, autoraise=True):
+ def open(self,
+ url,
+ new=0,
+ autoraise=True,
+ stdout=True,
+ stderr=True
+ ):
cmdline = [self.name] + [arg.replace("%s", url)
for arg in self.args]
+
+ redirect_stdout = _manage_fds(stdout)
+ redirect_stderr = _manage_fds(stderr)
+
try:
if sys.platform[:3] == 'win':
p = subprocess.Popen(cmdline)
@@ -162,7 +210,12 @@ class BackgroundBrowser(GenericBrowser):
setsid = getattr(os, 'setsid', None)
if not setsid:
setsid = getattr(os, 'setpgrp', None)
- p = subprocess.Popen(cmdline, close_fds=True, preexec_fn=setsid)
+ p = subprocess.Popen(cmdline,
+ close_fds=True,
+ stdout=redirect_stdout,
+ stderr=redirect_stderr,
+ preexec_fn=setsid
+ )
return (p.poll() is None)
except OSError:
return False
@@ -173,7 +226,6 @@ class UnixBrowser(BaseBrowser):
raise_opts = None
background = False
- redirect_stdout = True
# In remote_args, %s will be replaced with the requested URL. %action will
# be replaced depending on the value of 'new' passed to open.
# remote_action is used for new=0 (open). If newwin is not None, it is
@@ -185,13 +237,14 @@ class UnixBrowser(BaseBrowser):
remote_action_newwin = None
remote_action_newtab = None
- def _invoke(self, args, remote, autoraise):
+ def _invoke(self, args, remote, autoraise, stdout, stderr):
raise_opt = []
if remote and self.raise_opts:
# use autoraise argument only for remote invocation
autoraise = int(autoraise)
opt = self.raise_opts[autoraise]
- if opt: raise_opt = [opt]
+ if opt:
+ raise_opt = [opt]
cmdline = [self.name] + raise_opt + args
@@ -200,9 +253,10 @@ class UnixBrowser(BaseBrowser):
else:
# for TTY browsers, we need stdin/out
inout = None
+
p = subprocess.Popen(cmdline, close_fds=True, stdin=inout,
- stdout=(self.redirect_stdout and inout or None),
- stderr=inout, start_new_session=True)
+ stdout=stdout, stderr=stderr,
+ start_new_session=True)
if remote:
# wait at most five seconds. If the subprocess is not finished, the
# remote invocation has (hopefully) started a new instance.
@@ -220,7 +274,13 @@ class UnixBrowser(BaseBrowser):
else:
return not p.wait()
- def open(self, url, new=0, autoraise=True):
+ def open(self,
+ url,
+ new=0,
+ autoraise=True,
+ stdout=True,
+ stderr=True
+ ):
if new == 0:
action = self.remote_action
elif new == 1:
@@ -237,7 +297,15 @@ class UnixBrowser(BaseBrowser):
args = [arg.replace("%s", url).replace("%action", action)
for arg in self.remote_args]
args = [arg for arg in args if arg]
- success = self._invoke(args, True, autoraise)
+
+ redirect_stdout = _manage_fds(stdout)
+ redirect_stderr = _manage_fds(stderr)
+
+ success = self._invoke(args,
+ True,
+ autoraise,
+ redirect_stdout,
+ redirect_stderr)
if not success:
# remote invocation failed, try straight way
args = [arg.replace("%s", url) for arg in self.args]
@@ -313,7 +381,7 @@ class Konqueror(BaseBrowser):
for more information on the Konqueror remote-control interface.
"""
- def open(self, url, new=0, autoraise=True):
+ def open(self, url, new=0, autoraise=True, stdout=True, stderr=True):
# XXX Currently I know no way to prevent KFM from opening a new win.
if new == 2:
action = "newTab"
@@ -485,7 +553,8 @@ if os.environ.get("DISPLAY"):
if os.environ.get("TERM"):
if shutil.which("www-browser"):
register("www-browser", None, GenericBrowser("www-browser"))
- # The Links/elinks browsers
+ # The Links/elinks browsers
+ #
if shutil.which("links"):
register("links", None, GenericBrowser("links"))
if shutil.which("elinks"):
@@ -520,7 +589,8 @@ if sys.platform[:3] == "win":
register("windows-default", WindowsDefault)
# Detect some common Windows browsers, fallback to IE
- iexplore = os.path.join(os.environ.get("PROGRAMFILES", "C:\\Program Files"),
+ iexplore = os.path.join(os.environ.get("PROGRAMFILES",
+ "C:\\Program Files"),
"Internet Explorer\\IEXPLORE.EXE")
for browser in ("firefox", "firebird", "seamonkey", "mozilla",
"netscape", "opera", iexplore):
@@ -556,14 +626,16 @@ if sys.platform == 'darwin':
new = int(bool(new))
if self.name == "default":
# User called open, open_new or get without a browser parameter
- script = 'open location "%s"' % url.replace('"', '%22') # opens in default browser
+ # opens in default browser
+ script = 'open location "%s"' % url.replace('"', '%22')
else:
# User called get and chose a browser
if self.name == "OmniWeb":
toWindow = ""
else:
- # Include toWindow parameter of OpenURL command for browsers
- # that support it. 0 == new window; -1 == existing
+ # Include toWindow parameter of OpenURL command for
+ # browsers that support it.
+ # 0 == new window; -1 == existing
toWindow = "toWindow %d" % (new - 1)
cmd = 'OpenURL "%s"' % url.replace('"', '%22')
script = '''tell application "%s"
@@ -585,14 +657,15 @@ if sys.platform == 'darwin':
def open(self, url, new=0, autoraise=True):
if self._name == 'default':
- script = 'open location "%s"' % url.replace('"', '%22') # opens in default browser
+ # opens in default browser
+ script = 'open location "%s"' % url.replace('"', '%22')
else:
script = '''
tell application "%s"
activate
open location "%s"
end
- '''%(self._name, url.replace('"', '%22'))
+ ''' % (self._name, url.replace('"', '%22'))
osapipe = os.popen("osascript", "w")
if osapipe is None:
@@ -602,7 +675,6 @@ if sys.platform == 'darwin':
rc = osapipe.close()
return not rc
-
# Don't clear _tryorder or _browsers since OS X can use above Unix support
# (but we prefer using the OS X specific stuff)
register("safari", None, MacOSXOSAScript('safari'), -1)
@@ -623,7 +695,7 @@ if "BROWSER" in os.environ:
cmd = _synthesize(cmdline, -1)
if cmd[1] is None:
register(cmdline, None, GenericBrowser(cmdline), -1)
- cmdline = None # to make del work if _userchoices was empty
+ cmdline = None # to make del work if _userchoices was empty
del cmdline
del _userchoices
@@ -643,8 +715,10 @@ def main():
sys.exit(1)
new_win = 0
for o, a in opts:
- if o == '-n': new_win = 1
- elif o == '-t': new_win = 2
+ if o == '-n':
+ new_win = 1
+ elif o == '-t':
+ new_win = 2
if len(args) != 1:
print(usage, file=sys.stderr)
sys.exit(1)