Viewing file: webbrowser.py (11.28 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
"""Interfaces for launching and remotely controlling Web browsers."""
import os import sys
__all__ = ["Error", "open", "get", "register"]
class Error(Exception): pass
_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.""" if using is not None: alternatives = [using] else: alternatives = _tryorder for browser in alternatives: if '%s' in browser: # User gave us a command line, don't mess with it. return GenericBrowser(browser) else: # User gave us a browser name. try: command = _browsers[browser.lower()] except KeyError: command = _synthesize(browser) if command[1] is None: return command[0]() else: return command[1] 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 an entry in the BROWSER environment variable -- we can copy a general controller to operate using a specific installation of the desired browser in this way.
If we can't create a controller in this way, or if there is no 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: return [None, None] # now attempt to clone to fit the new name: controller = command[1] if controller and name.lower() == controller.basename: import copy 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! def _find_grail_rc(self): import glob import pwd import socket import tempfile tempdir = os.path.join(tempfile.gettempdir(), ".grail-unix") user = pwd.getpwuid(os.getuid())[0] filename = os.path.join(tempdir, user + "-*") maybes = glob.glob(filename) if not maybes: return None s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) for fn in maybes: # need to PING each one until we find one that's live try: s.connect(fn) except socket.error: # no good; attempt to clean it out, but don't fail: try: os.unlink(fn) except IOError: pass else: return s
def _remote(self, action): s = self._find_grail_rc() if not s: return 0 s.send(action) s.close() return 1
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 <http://artax.karlin.mff.cuni.cz/~mikulas/links/> if _iscommand("links"): register("links", None, GenericBrowser("links '%s'")) # The Lynx browser <http://lynx.browser.org/> if _iscommand("lynx"): register("lynx", None, GenericBrowser("lynx '%s'")) # The w3m browser <http://ei5nazha.yz.yamagata-u.ac.jp/~aito/w3m/eng/> if _iscommand("w3m"): register("w3m", None, GenericBrowser("w3m '%s'"))
# X browsers have more in the way of options if os.environ.get("DISPLAY"): _tryorder = ["htmlview", "firefox", "galeon", "skipstone", "mozilla-firefox", "mozilla-firebird", "mozilla", "netscape", "kfm", "grail"] + _tryorder
# Try htmlview (in order to honor user config) before anything else. if _iscommand("htmlview"): register("htmlview", None, GenericBrowser( "htmlview '%s' >/dev/null &"))
# First, the Netscape series for browser in ("firefox", "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)
# # Platform support for MacOS #
try: import ic 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[0:0] = 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?
|