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