*** webbrowser.py.orig Thu Dec 16 18:47:38 2004
--- webbrowser.py Wed Mar 30 14:45:57 2005
***************
*** 1,7 ****
--- 1,9 ----
+ #! /usr/bin/env python
"""Interfaces for launching and remotely controlling Web browsers."""
import os
import sys
+ import stat
__all__ = ["Error", "open", "get", "register"]
***************
*** 11,19 ****
_browsers = {} # Dictionary of available browser controllers
_tryorder = [] # Preference order of available browsers
! def register(name, klass, instance=None):
"""Register a browser connector and, optionally, connection."""
_browsers[name.lower()] = [klass, instance]
def get(using=None):
"""Return a browser launcher instance appropriate for the environment."""
--- 13,25 ----
_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]
+ if update_tryorder > 0:
+ _tryorder.append(name)
+ elif update_tryorder < 0:
+ _tryorder.insert(0, name)
def get(using=None):
"""Return a browser launcher instance appropriate for the environment."""
***************
*** 38,52 ****
raise Error("could not locate runnable browser")
# Please note: the following definition hides a builtin function.
def open(url, new=0, autoraise=1):
! get().open(url, new, autoraise)
! def open_new(url):
! get().open(url, 1)
! def _synthesize(browser):
"""Attempt to synthesize a controller base on existing controllers.
This is useful to create a controller when a user specifies a path to
--- 44,69 ----
raise Error("could not locate runnable browser")
# Please note: the following definition hides a builtin function.
+ # It is recommended one does "import webbrowser" and uses webbrowser.open(url)
+ # instead of "from webbrowser import *".
def open(url, new=0, autoraise=1):
! for name in _tryorder:
! browser = get(name)
! if browser.open(url, new, autoraise):
! return True
! return False
!
! def open_new_win(url):
! return open(url, 1)
! open_new = open_new_win
+ def open_new_tab(url):
+ return open(url, 2)
!
! def _synthesize(browser, update_tryorder=1):
"""Attempt to synthesize a controller base on existing controllers.
This is useful to create a controller when a user specifies a path to
***************
*** 58,66 ****
executable for the requested browser, return [None, None].
"""
! if not os.path.exists(browser):
return [None, None]
! name = os.path.basename(browser)
try:
command = _browsers[name.lower()]
except KeyError:
--- 75,84 ----
executable for the requested browser, return [None, None].
"""
! cmd = browser.split()[0]
! if not _iscommand(cmd):
return [None, None]
! name = os.path.basename(cmd)
try:
command = _browsers[name.lower()]
except KeyError:
***************
*** 72,203 ****
controller = copy.copy(controller)
controller.name = browser
controller.basename = os.path.basename(browser)
! register(browser, None, controller)
return [None, controller]
return [None, None]
def _iscommand(cmd):
! """Return True if cmd can be found on the executable search path."""
path = os.environ.get("PATH")
if not path:
! return False
for d in path.split(os.pathsep):
exe = os.path.join(d, cmd)
! if os.path.isfile(exe):
! return True
! return False
! PROCESS_CREATION_DELAY = 4
- class GenericBrowser:
- def __init__(self, cmd):
- self.name, self.args = cmd.split(None, 1)
- self.basename = os.path.basename(self.name)
! def open(self, url, new=0, autoraise=1):
! assert "'" not in url
! command = "%s %s" % (self.name, self.args)
! os.system(command % url)
! def open_new(self, url):
! self.open(url)
- class Netscape:
- "Launcher class for Netscape browsers."
def __init__(self, name):
self.name = name
self.basename = os.path.basename(name)
! def _remote(self, action, autoraise):
! raise_opt = ("-noraise", "-raise")[autoraise]
! cmd = "%s %s -remote '%s' >/dev/null 2>&1" % (self.name,
! raise_opt,
! action)
! rc = os.system(cmd)
if rc:
! import time
! os.system("%s &" % self.name)
! time.sleep(PROCESS_CREATION_DELAY)
! rc = os.system(cmd)
return not rc
def open(self, url, new=0, autoraise=1):
! if new:
! self._remote("openURL(%s, new-window)"%url, autoraise)
else:
! self._remote("openURL(%s)" % url, autoraise)
! def open_new(self, url):
! self.open(url, 1)
! class Galeon:
! """Launcher class for Galeon browsers."""
! def __init__(self, name):
! self.name = name
! self.basename = os.path.basename(name)
! def _remote(self, action, autoraise):
! raise_opt = ("--noraise", "")[autoraise]
! cmd = "%s %s %s >/dev/null 2>&1" % (self.name, raise_opt, action)
! rc = os.system(cmd)
! if rc:
! import time
! os.system("%s >/dev/null 2>&1 &" % self.name)
! time.sleep(PROCESS_CREATION_DELAY)
! rc = os.system(cmd)
! return not rc
def open(self, url, new=0, autoraise=1):
! if new:
! self._remote("-w '%s'" % url, autoraise)
! else:
! self._remote("-n '%s'" % url, autoraise)
! def open_new(self, url):
! self.open(url, 1)
! class Konqueror:
"""Controller for the KDE File Manager (kfm, or Konqueror).
See http://developer.kde.org/documentation/other/kfmclient.html
for more information on the Konqueror remote-control interface.
"""
def __init__(self):
if _iscommand("konqueror"):
self.name = self.basename = "konqueror"
else:
self.name = self.basename = "kfm"
! def _remote(self, action):
cmd = "kfmclient %s >/dev/null 2>&1" % action
! rc = os.system(cmd)
if rc:
- import time
if self.basename == "konqueror":
! os.system(self.name + " --silent &")
else:
! os.system(self.name + " -d &")
! time.sleep(PROCESS_CREATION_DELAY)
! rc = os.system(cmd)
return not rc
def open(self, url, new=1, autoraise=1):
# XXX Currently I know no way to prevent KFM from
# opening a new win.
assert "'" not in url
! self._remote("openURL '%s'" % url)
! open_new = open
! class Grail:
# There should be a way to maintain a connection to Grail, but the
# Grail remote control protocol doesn't really allow that at this
# point. It probably neverwill!
--- 90,302 ----
controller = copy.copy(controller)
controller.name = browser
controller.basename = os.path.basename(browser)
! register(browser, None, controller, update_tryorder)
return [None, controller]
return [None, None]
+ if sys.platform[:3] == "win":
+ def _isexecutable(cmd):
+ cmd = cmd.lower()
+ if os.path.isfile(cmd) and (
+ cmd.endswith(".exe") or cmd.endswith(".bat")):
+ return True
+ for ext in ".exe", ".bat":
+ if os.path.isfile(cmd + ext):
+ return True
+ return False
+ else:
+ def _isexecutable(cmd):
+ if os.path.isfile(cmd):
+ mode = os.stat(cmd)[stat.ST_MODE]
+ if mode & stat.S_IXUSR or mode & stat.S_IXGRP or mode & stat.S_IXOTH:
+ return True
+ return False
+
def _iscommand(cmd):
! """Return True if cmd is executable or can be found on the executable
! search path."""
! if _isexecutable(cmd):
! return cmd
path = os.environ.get("PATH")
if not path:
! return None
for d in path.split(os.pathsep):
exe = os.path.join(d, cmd)
! if _isexecutable(exe):
! return exe
! return None
! _DEBUG = 0 # debug level
+ def _run(cmd):
+ if _DEBUG >= 2:
+ print "Running command '%s'" % cmd
+ rc = os.system(cmd)
+ if _DEBUG >= 2:
+ print " result: %d" % rc
+ return rc
! # General parent classes
! class NoNewTab(object):
! """For browsers that don't support new-tab functionality"""
+ def open_new_tab(self, url):
+ return self.open_new_win(url)
+
+ class UnixBrowser(NoNewTab):
+ "Parent class for all Unix browsers"
+
+ raise_opts = None
+
+ remote_cmd = ''
+ remote_action = None
+ remote_action_newwin = None
+ remote_action_newtab = None
def __init__(self, name):
self.name = name
self.basename = os.path.basename(name)
! def _remote(self, url, action, autoraise):
! raise_opt = self.raise_opts and self.raise_opts[autoraise] or ''
! cmd = "%s %s %s '%s' >/dev/null 2>&1" % (self.name, raise_opt,
! self.remote_cmd, action)
! rc = _run(cmd)
if rc:
! rc = _run("%s %s" % (self.name, url))
return not rc
def open(self, url, new=0, autoraise=1):
! assert "'" not in url
! if new == 0:
! action = self.remote_action
! elif new == 1:
! action = self.remote_action_newwin
! elif new == 2:
! if self.remote_action_newtab is None:
! action = self.remote_action_newwin
! else:
! action = self.remote_action_newtab
else:
! raise Error("Bad 'new' parameter to open(); expected 0, 1, or 2, got %s" % new)
! return self._remote(url, action % url, autoraise)
! def open_new_win(self, url):
! return self.open(url, 1)
+ open_new = open_new_win
! def open_new_tab(self, url):
! return self.open(url, 2)
!
! class GenericBrowser(NoNewTab):
! def __init__(self, cmd):
! self.name, self.args = cmd.split(None, 1)
! self.basename = os.path.basename(self.name)
def open(self, url, new=0, autoraise=1):
! assert "'" not in url
! command = "%s %s" % (self.name, self.args)
! rc = _run(command % url)
! return not rc
!
! def open_new_win(self, url):
! return self.open(url)
!
! open_new = open_new_win
!
!
! class Mozilla(UnixBrowser):
! "Launcher class for Mozilla/Netscape browsers."
!
! raise_opts = ("-noraise", "-raise")
!
! remote_cmd = '-remote'
! remote_action = "openURL(%s)"
! remote_action_newwin = "openURL(%s,new-window)"
! remote_action_newtab = "openURL(%s,new-tab)"
!
! Netscape = Mozilla
!
!
! class Galeon(UnixBrowser):
! """Launcher class for Galeon/Epiphany browsers."""
! raise_opts = ("-noraise", "")
! remote_action = "-n '%s'"
! remote_action_newwin = "-w '%s'"
! class Konqueror(NoNewTab):
"""Controller for the KDE File Manager (kfm, or Konqueror).
See http://developer.kde.org/documentation/other/kfmclient.html
for more information on the Konqueror remote-control interface.
"""
+
def __init__(self):
if _iscommand("konqueror"):
self.name = self.basename = "konqueror"
else:
self.name = self.basename = "kfm"
! def _remote(self, url, action):
cmd = "kfmclient %s >/dev/null 2>&1" % action
! rc = _run(cmd)
if rc:
if self.basename == "konqueror":
! rc = _run(self.name + " --silent '%s'" % url)
else:
! rc = _run(self.name + " -d '%s'" % url)
return not rc
def open(self, url, new=1, autoraise=1):
# XXX Currently I know no way to prevent KFM from
# opening a new win.
assert "'" not in url
! ok = self._remote(url, "openURL '%s'" % url)
! return ok
!
! open_new_win = open_new = open
!
!
! class Opera(UnixBrowser):
! "Launcher class for Opera browser."
! raise_opts = ("", "-raise")
+ remote_cmd = '-remote'
+ remote_action = "openURL(%s)"
+ remote_action_newwin = "openURL(%s,new-window)"
+ remote_action_newtab = "openURL(%s,new-page)"
!
! class Elinks(UnixBrowser):
! "Launcher class for Elinks browsers."
!
! remote_cmd = '-remote'
! remote_action = "openURL(%s)"
! remote_action_newwin = "openURL(%s,new-window)"
! remote_action_newtab = "openURL(%s,new-tab)"
!
! def _remote(self, url, action, autoraise):
! # elinks doesn't like its stdout to be redirected -
! # it uses redirected stdout as a signal to do -dump
! cmd = "%s %s '%s' 2>/dev/null" % (self.name,
! self.remote_cmd, action)
! rc = _run(cmd)
! if rc:
! rc = _run("%s %s" % (self.name, url))
! return not rc
!
!
! class Grail(NoNewTab):
# There should be a way to maintain a connection to Grail, but the
# Grail remote control protocol doesn't really allow that at this
# point. It probably neverwill!
***************
*** 237,329 ****
def open(self, url, new=0, autoraise=1):
if new:
! self._remote("LOADNEW " + url)
else:
! self._remote("LOAD " + url)
! def open_new(self, url):
! self.open(url, 1)
!
! class WindowsDefault:
! def open(self, url, new=0, autoraise=1):
! os.startfile(url)
!
! def open_new(self, url):
! self.open(url)
#
# Platform support for Unix
#
! # This is the right test because all these Unix browsers require either
! # a console terminal of an X display to run. Note that we cannot split
! # the TERM and DISPLAY cases, because we might be running Python from inside
! # an xterm.
! if os.environ.get("TERM") or os.environ.get("DISPLAY"):
! _tryorder = ["links", "lynx", "w3m"]
!
! # Easy cases first -- register console browsers if we have them.
! if os.environ.get("TERM"):
! # The Links browser
! if _iscommand("links"):
! register("links", None, GenericBrowser("links '%s'"))
! # The Lynx browser
! if _iscommand("lynx"):
! register("lynx", None, GenericBrowser("lynx '%s'"))
! # The w3m browser
! if _iscommand("w3m"):
! register("w3m", None, GenericBrowser("w3m '%s'"))
!
! # X browsers have more in the way of options
! if os.environ.get("DISPLAY"):
! _tryorder = ["galeon", "skipstone",
! "mozilla-firefox", "mozilla-firebird", "mozilla", "netscape",
! "kfm", "grail"] + _tryorder
!
! # First, the Netscape series
! for browser in ("mozilla-firefox", "mozilla-firebird",
! "mozilla", "netscape"):
! if _iscommand(browser):
! register(browser, None, Netscape(browser))
!
! # Next, Mosaic -- old but still in use.
! if _iscommand("mosaic"):
! register("mosaic", None, GenericBrowser(
! "mosaic '%s' >/dev/null &"))
!
! # Gnome's Galeon
! if _iscommand("galeon"):
! register("galeon", None, Galeon("galeon"))
!
! # Skipstone, another Gtk/Mozilla based browser
! if _iscommand("skipstone"):
! register("skipstone", None, GenericBrowser(
! "skipstone '%s' >/dev/null &"))
!
! # Konqueror/kfm, the KDE browser.
! if _iscommand("kfm") or _iscommand("konqueror"):
! register("kfm", Konqueror, Konqueror())
!
! # Grail, the Python browser.
! if _iscommand("grail"):
! register("grail", Grail, None)
!
!
! class InternetConfig:
! def open(self, url, new=0, autoraise=1):
! ic.launchurl(url)
! def open_new(self, url):
! self.open(url)
#
# Platform support for Windows
#
if sys.platform[:3] == "win":
! _tryorder = ["netscape", "windows-default"]
register("windows-default", WindowsDefault)
#
--- 336,427 ----
def open(self, url, new=0, autoraise=1):
if new:
! ok = self._remote("LOADNEW " + url)
else:
! ok = self._remote("LOAD " + url)
! return ok
! def open_new_win(self, url):
! return self.open(url, 1)
! open_new = open_new_win
#
# Platform support for Unix
#
! # These are the right tests because all these Unix browsers require either
! # a console terminal or an X display to run.
! # Prefer X browsers if present
! if os.environ.get("DISPLAY"):
+ # First, the Mozilla/Netscape browsers
+ for browser in ("mozilla", "mozilla-firefox", "mozilla-firebird",
+ "firefox", "firebird", "netscape"):
+ if _iscommand(browser):
+ register(browser, None, Mozilla(browser))
+
+ # Gnome's Galeon and Epiphany
+ for browser in ("galeon", "epiphany"):
+ if _iscommand(browser):
+ register(browser, None, Galeon(browser))
+
+ # Skipstone, another Gtk/Mozilla based browser
+ if _iscommand("skipstone"):
+ register("skipstone", None, GenericBrowser("skipstone '%s'"))
+
+ # Konqueror/kfm, the KDE browser.
+ if _iscommand("kfm") or _iscommand("konqueror"):
+ register("kfm", Konqueror, Konqueror())
+
+ # Next, Mosaic -- old but still in use.
+ if _iscommand("mosaic"):
+ register("mosaic", None, GenericBrowser("mosaic '%s'"))
+
+ # Opera, quite popular
+ if _iscommand("opera"):
+ register("opera", None, Opera("opera"))
+
+ # Grail, the Python browser.
+ if _iscommand("grail"):
+ register("grail", Grail, None)
+
+ # Also try console browsers
+ if os.environ.get("TERM"):
+ # The Links/elinks browsers
+ if _iscommand("links"):
+ register("links", None, GenericBrowser("links '%s'"))
+ if _iscommand("elinks"):
+ register("elinks", None, Elinks("elinks"))
+ # The Lynx browser ,
+ if _iscommand("lynx"):
+ register("lynx", None, GenericBrowser("lynx '%s'"))
+ # The w3m browser
+ if _iscommand("w3m"):
+ register("w3m", None, GenericBrowser("w3m '%s'"))
#
# Platform support for Windows
#
if sys.platform[:3] == "win":
! class WindowsDefault(NoNewTab):
! def open(self, url, new=0, autoraise=1):
! os.startfile(url)
! return True # Oh, my...
!
! def open_new_win(self, url):
! return self.open(url)
!
! open_new = open_new_win
!
! _tryorder = []
! _browsers = {}
! # Prefer mozilla/netscape/opera if present
! for browser in ("mozilla", "firefox", "firebird", "netscape", "opera"):
! if _iscommand(browser):
! register(browser, None, GenericBrowser(browser + ' %s'))
register("windows-default", WindowsDefault)
#
***************
*** 335,370 ****
except ImportError:
pass
else:
! # internet-config is the only supported controller on MacOS,
! # so don't mess with the default!
! _tryorder = ["internet-config"]
! register("internet-config", InternetConfig)
#
# Platform support for OS/2
#
! if sys.platform[:3] == "os2" and _iscommand("netscape.exe"):
! _tryorder = ["os2netscape"]
register("os2netscape", None,
! GenericBrowser("start netscape.exe %s"))
# OK, now that we know what the default preference orders for each
# platform are, allow user to override them with the BROWSER variable.
- #
if "BROWSER" in os.environ:
! # It's the user's responsibility to register handlers for any unknown
! # browser referenced by this value, before calling open().
! _tryorder = os.environ["BROWSER"].split(os.pathsep)
!
! for cmd in _tryorder:
! if not cmd.lower() in _browsers:
! if _iscommand(cmd.lower()):
! register(cmd.lower(), None, GenericBrowser(
! "%s '%%s'" % cmd.lower()))
! cmd = None # to make del work if _tryorder was empty
! del cmd
- _tryorder = filter(lambda x: x.lower() in _browsers
- or x.find("%s") > -1, _tryorder)
# what to do if _tryorder is now empty?
--- 433,559 ----
except ImportError:
pass
else:
! class InternetConfig(NoNewTab):
! def open(self, url, new=0, autoraise=1):
! ic.launchurl(url)
! return True # Any way to get status?
!
! def open_new_win(self, url):
! return self.open(url)
!
! open_new = open_new_win
!
! register("internet-config", InternetConfig, update_tryorder=-1)
!
! if sys.platform == 'darwin':
! # Adapted from patch submitted to SourceForge by Steven J. Burr
! class MacOSX(NoNewTab):
! """Launcher class for Aqua browsers on Mac OS X
!
! Optionally specify a browser name on instantiation. Note that this
! will not work for Aqua browsers if the user has moved the application
! package after installation.
!
! If no browser is specified, the default browser, as specified in the
! Internet System Preferences panel, will be used.
! """
! def __init__(self, name):
! self.name = name
!
! def open(self, url, new=0, autoraise=1):
! assert "'" not in url
! if self.name == "default":
! # User called open, open_new or get without a browser parameter
! script = _safequote('open location "%s"', url) # opens in default browser
! 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
! toWindow = "toWindow %d" % (new - 1)
! cmd = _safequote('OpenURL "%s"', url)
! script = '''tell application "%s"
! activate
! %s %s
! end tell''' % (self.name, cmd, toWindow)
! # Open pipe to AppleScript through osascript command
! osapipe = os.popen("osascript", "w")
! if osapipe is None:
! return False
! # Write script to osascript's stdin
! osapipe.write(script)
! rc = osapipe.close()
! return not rc
!
! def open_new_win(self, url):
! return self.open(url, 1)
!
! open_new = open_new_win
!
! # Don't clear _tryorder or _browsers since OS X can use above Unix support
! # (but we prefer using the OS X specific stuff)
! register("MacOSX", None, MacOSX('default'), -1)
!
#
# Platform support for OS/2
#
! if sys.platform[:3] == "os2" and _iscommand("netscape"):
! _tryorder = []
! _browsers = {}
register("os2netscape", None,
! GenericBrowser("start netscape %s"), -1)
!
# OK, now that we know what the default preference orders for each
# platform are, allow user to override them with the BROWSER variable.
if "BROWSER" in os.environ:
! _userchoices = os.environ["BROWSER"].split(os.pathsep)
! _userchoices.reverse()
!
! # Treat choices in same way as if passed into get() but do register
! # and prepend to _tryorder
! for cmdline in _userchoices:
! if cmdline != '':
! _synthesize(cmdline, -1)
! cmdline = None # to make del work if _userchoices was empty
! del cmdline
! del _userchoices
# what to do if _tryorder is now empty?
+
+
+ def main():
+ global _DEBUG
+ import getopt
+ usage = """Usage: %s [-n | -t] url
+ -n: open new window
+ -t: open new tab""" % sys.argv[0]
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], 'ntd')
+ except getopt.error, msg:
+ print >>sys.stderr, msg
+ print >>sys.stderr, usage
+ sys.exit(1)
+ new_win = 0
+ for o, a in opts:
+ if o == '-n': new_win = 1
+ elif o == '-t': new_win = 2
+ elif o == '-d': _DEBUG += 1
+ if len(args) <> 1:
+ print >>sys.stderr, usage
+ sys.exit(1)
+
+ if _DEBUG:
+ print "Try order:", _tryorder
+ print "Browsers:", _browsers
+ url = args[0]
+ ok = open(url, new_win)
+ if _DEBUG:
+ print "Result:", ok
+
+ if __name__ == "__main__":
+ main()