]>
git.proxmox.com Git - mirror_edk2.git/blob - AppPkg/Applications/Python/Python-2.7.2/Lib/webbrowser.py
2 """Interfaces for launching and remotely controlling Web browsers."""
3 # Maintained by Georg Brandl.
12 __all__
= ["Error", "open", "open_new", "open_new_tab", "get", "register"]
14 class Error(Exception):
17 _browsers
= {} # Dictionary of available browser controllers
18 _tryorder
= [] # Preference order of available browsers
20 def register(name
, klass
, instance
=None, update_tryorder
=1):
21 """Register a browser connector and, optionally, connection."""
22 _browsers
[name
.lower()] = [klass
, instance
]
23 if update_tryorder
> 0:
24 _tryorder
.append(name
)
25 elif update_tryorder
< 0:
26 _tryorder
.insert(0, name
)
29 """Return a browser launcher instance appropriate for the environment."""
31 alternatives
= [using
]
33 alternatives
= _tryorder
34 for browser
in alternatives
:
36 # User gave us a command line, split it into name and args
37 browser
= shlex
.split(browser
)
38 if browser
[-1] == '&':
39 return BackgroundBrowser(browser
[:-1])
41 return GenericBrowser(browser
)
43 # User gave us a browser name or path.
45 command
= _browsers
[browser
.lower()]
47 command
= _synthesize(browser
)
48 if command
[1] is not None:
50 elif command
[0] is not None:
52 raise Error("could not locate runnable browser")
54 # Please note: the following definition hides a builtin function.
55 # It is recommended one does "import webbrowser" and uses webbrowser.open(url)
56 # instead of "from webbrowser import *".
58 def open(url
, new
=0, autoraise
=True):
59 for name
in _tryorder
:
61 if browser
.open(url
, new
, autoraise
):
68 def open_new_tab(url
):
72 def _synthesize(browser
, update_tryorder
=1):
73 """Attempt to synthesize a controller base on existing controllers.
75 This is useful to create a controller when a user specifies a path to
76 an entry in the BROWSER environment variable -- we can copy a general
77 controller to operate using a specific installation of the desired
80 If we can't create a controller in this way, or if there is no
81 executable for the requested browser, return [None, None].
84 cmd
= browser
.split()[0]
85 if not _iscommand(cmd
):
87 name
= os
.path
.basename(cmd
)
89 command
= _browsers
[name
.lower()]
92 # now attempt to clone to fit the new name:
93 controller
= command
[1]
94 if controller
and name
.lower() == controller
.basename
:
96 controller
= copy
.copy(controller
)
97 controller
.name
= browser
98 controller
.basename
= os
.path
.basename(browser
)
99 register(browser
, None, controller
, update_tryorder
)
100 return [None, controller
]
104 if sys
.platform
[:3] == "win":
105 def _isexecutable(cmd
):
107 if os
.path
.isfile(cmd
) and cmd
.endswith((".exe", ".bat")):
109 for ext
in ".exe", ".bat":
110 if os
.path
.isfile(cmd
+ ext
):
114 def _isexecutable(cmd
):
115 if os
.path
.isfile(cmd
):
116 mode
= os
.stat(cmd
)[stat
.ST_MODE
]
117 if mode
& stat
.S_IXUSR
or mode
& stat
.S_IXGRP
or mode
& stat
.S_IXOTH
:
122 """Return True if cmd is executable or can be found on the executable
124 if _isexecutable(cmd
):
126 path
= os
.environ
.get("PATH")
129 for d
in path
.split(os
.pathsep
):
130 exe
= os
.path
.join(d
, cmd
)
131 if _isexecutable(exe
):
136 # General parent classes
138 class BaseBrowser(object):
139 """Parent class for all browsers. Do not use directly."""
143 def __init__(self
, name
=""):
147 def open(self
, url
, new
=0, autoraise
=True):
148 raise NotImplementedError
150 def open_new(self
, url
):
151 return self
.open(url
, 1)
153 def open_new_tab(self
, url
):
154 return self
.open(url
, 2)
157 class GenericBrowser(BaseBrowser
):
158 """Class for all browsers started with a command
159 and without remote functionality."""
161 def __init__(self
, name
):
162 if isinstance(name
, basestring
):
166 # name should be a list with arguments
169 self
.basename
= os
.path
.basename(self
.name
)
171 def open(self
, url
, new
=0, autoraise
=True):
172 cmdline
= [self
.name
] + [arg
.replace("%s", url
)
173 for arg
in self
.args
]
175 if sys
.platform
[:3] == 'win':
176 p
= subprocess
.Popen(cmdline
)
178 p
= subprocess
.Popen(cmdline
, close_fds
=True)
184 class BackgroundBrowser(GenericBrowser
):
185 """Class for all browsers which are to be started in the
188 def open(self
, url
, new
=0, autoraise
=True):
189 cmdline
= [self
.name
] + [arg
.replace("%s", url
)
190 for arg
in self
.args
]
192 if sys
.platform
[:3] == 'win':
193 p
= subprocess
.Popen(cmdline
)
195 setsid
= getattr(os
, 'setsid', None)
197 setsid
= getattr(os
, 'setpgrp', None)
198 p
= subprocess
.Popen(cmdline
, close_fds
=True, preexec_fn
=setsid
)
199 return (p
.poll() is None)
204 class UnixBrowser(BaseBrowser
):
205 """Parent class for all Unix browsers with remote functionality."""
208 remote_args
= ['%action', '%s']
210 remote_action_newwin
= None
211 remote_action_newtab
= None
213 redirect_stdout
= True
215 def _invoke(self
, args
, remote
, autoraise
):
217 if remote
and self
.raise_opts
:
218 # use autoraise argument only for remote invocation
219 autoraise
= int(autoraise
)
220 opt
= self
.raise_opts
[autoraise
]
221 if opt
: raise_opt
= [opt
]
223 cmdline
= [self
.name
] + raise_opt
+ args
225 if remote
or self
.background
:
226 inout
= file(os
.devnull
, "r+")
228 # for TTY browsers, we need stdin/out
230 # if possible, put browser in separate process group, so
231 # keyboard interrupts don't affect browser as well as Python
232 setsid
= getattr(os
, 'setsid', None)
234 setsid
= getattr(os
, 'setpgrp', None)
236 p
= subprocess
.Popen(cmdline
, close_fds
=True, stdin
=inout
,
237 stdout
=(self
.redirect_stdout
and inout
or None),
238 stderr
=inout
, preexec_fn
=setsid
)
240 # wait five secons. If the subprocess is not finished, the
241 # remote invocation has (hopefully) started a new instance.
249 # if remote call failed, open() will try direct invocation
251 elif self
.background
:
259 def open(self
, url
, new
=0, autoraise
=True):
261 action
= self
.remote_action
263 action
= self
.remote_action_newwin
265 if self
.remote_action_newtab
is None:
266 action
= self
.remote_action_newwin
268 action
= self
.remote_action_newtab
270 raise Error("Bad 'new' parameter to open(); " +
271 "expected 0, 1, or 2, got %s" % new
)
273 args
= [arg
.replace("%s", url
).replace("%action", action
)
274 for arg
in self
.remote_args
]
275 success
= self
._invoke
(args
, True, autoraise
)
277 # remote invocation failed, try straight way
278 args
= [arg
.replace("%s", url
) for arg
in self
.args
]
279 return self
._invoke
(args
, False, False)
284 class Mozilla(UnixBrowser
):
285 """Launcher class for Mozilla/Netscape browsers."""
287 raise_opts
= ["-noraise", "-raise"]
288 remote_args
= ['-remote', 'openURL(%s%action)']
290 remote_action_newwin
= ",new-window"
291 remote_action_newtab
= ",new-tab"
297 class Galeon(UnixBrowser
):
298 """Launcher class for Galeon/Epiphany browsers."""
300 raise_opts
= ["-noraise", ""]
301 remote_args
= ['%action', '%s']
303 remote_action_newwin
= "-w"
307 class Opera(UnixBrowser
):
308 "Launcher class for Opera browser."
310 raise_opts
= ["-noraise", ""]
311 remote_args
= ['-remote', 'openURL(%s%action)']
313 remote_action_newwin
= ",new-window"
314 remote_action_newtab
= ",new-page"
318 class Elinks(UnixBrowser
):
319 "Launcher class for Elinks browsers."
321 remote_args
= ['-remote', 'openURL(%s%action)']
323 remote_action_newwin
= ",new-window"
324 remote_action_newtab
= ",new-tab"
327 # elinks doesn't like its stdout to be redirected -
328 # it uses redirected stdout as a signal to do -dump
329 redirect_stdout
= False
332 class Konqueror(BaseBrowser
):
333 """Controller for the KDE File Manager (kfm, or Konqueror).
335 See the output of ``kfmclient --commands``
336 for more information on the Konqueror remote-control interface.
339 def open(self
, url
, new
=0, autoraise
=True):
340 # XXX Currently I know no way to prevent KFM from opening a new win.
346 devnull
= file(os
.devnull
, "r+")
347 # if possible, put browser in separate process group, so
348 # keyboard interrupts don't affect browser as well as Python
349 setsid
= getattr(os
, 'setsid', None)
351 setsid
= getattr(os
, 'setpgrp', None)
354 p
= subprocess
.Popen(["kfmclient", action
, url
],
355 close_fds
=True, stdin
=devnull
,
356 stdout
=devnull
, stderr
=devnull
)
358 # fall through to next variant
362 # kfmclient's return code unfortunately has no meaning as it seems
366 p
= subprocess
.Popen(["konqueror", "--silent", url
],
367 close_fds
=True, stdin
=devnull
,
368 stdout
=devnull
, stderr
=devnull
,
371 # fall through to next variant
375 # Should be running now.
379 p
= subprocess
.Popen(["kfm", "-d", url
],
380 close_fds
=True, stdin
=devnull
,
381 stdout
=devnull
, stderr
=devnull
,
386 return (p
.poll() is None)
389 class Grail(BaseBrowser
):
390 # There should be a way to maintain a connection to Grail, but the
391 # Grail remote control protocol doesn't really allow that at this
392 # point. It probably never will!
393 def _find_grail_rc(self
):
398 tempdir
= os
.path
.join(tempfile
.gettempdir(),
400 user
= pwd
.getpwuid(os
.getuid())[0]
401 filename
= os
.path
.join(tempdir
, user
+ "-*")
402 maybes
= glob
.glob(filename
)
405 s
= socket
.socket(socket
.AF_UNIX
, socket
.SOCK_STREAM
)
407 # need to PING each one until we find one that's live
411 # no good; attempt to clean it out, but don't fail:
419 def _remote(self
, action
):
420 s
= self
._find
_grail
_rc
()
427 def open(self
, url
, new
=0, autoraise
=True):
429 ok
= self
._remote
("LOADNEW " + url
)
431 ok
= self
._remote
("LOAD " + url
)
436 # Platform support for Unix
439 # These are the right tests because all these Unix browsers require either
440 # a console terminal or an X display to run.
442 def register_X_browsers():
444 # The default GNOME browser
445 if "GNOME_DESKTOP_SESSION_ID" in os
.environ
and _iscommand("gnome-open"):
446 register("gnome-open", None, BackgroundBrowser("gnome-open"))
448 # The default KDE browser
449 if "KDE_FULL_SESSION" in os
.environ
and _iscommand("kfmclient"):
450 register("kfmclient", Konqueror
, Konqueror("kfmclient"))
452 # The Mozilla/Netscape browsers
453 for browser
in ("mozilla-firefox", "firefox",
454 "mozilla-firebird", "firebird",
455 "seamonkey", "mozilla", "netscape"):
456 if _iscommand(browser
):
457 register(browser
, None, Mozilla(browser
))
459 # Konqueror/kfm, the KDE browser.
460 if _iscommand("kfm"):
461 register("kfm", Konqueror
, Konqueror("kfm"))
462 elif _iscommand("konqueror"):
463 register("konqueror", Konqueror
, Konqueror("konqueror"))
465 # Gnome's Galeon and Epiphany
466 for browser
in ("galeon", "epiphany"):
467 if _iscommand(browser
):
468 register(browser
, None, Galeon(browser
))
470 # Skipstone, another Gtk/Mozilla based browser
471 if _iscommand("skipstone"):
472 register("skipstone", None, BackgroundBrowser("skipstone"))
474 # Opera, quite popular
475 if _iscommand("opera"):
476 register("opera", None, Opera("opera"))
478 # Next, Mosaic -- old but still in use.
479 if _iscommand("mosaic"):
480 register("mosaic", None, BackgroundBrowser("mosaic"))
482 # Grail, the Python browser. Does anybody still use it?
483 if _iscommand("grail"):
484 register("grail", Grail
, None)
486 # Prefer X browsers if present
487 if os
.environ
.get("DISPLAY"):
488 register_X_browsers()
490 # Also try console browsers
491 if os
.environ
.get("TERM"):
492 # The Links/elinks browsers <http://artax.karlin.mff.cuni.cz/~mikulas/links/>
493 if _iscommand("links"):
494 register("links", None, GenericBrowser("links"))
495 if _iscommand("elinks"):
496 register("elinks", None, Elinks("elinks"))
497 # The Lynx browser <http://lynx.isc.org/>, <http://lynx.browser.org/>
498 if _iscommand("lynx"):
499 register("lynx", None, GenericBrowser("lynx"))
500 # The w3m browser <http://w3m.sourceforge.net/>
501 if _iscommand("w3m"):
502 register("w3m", None, GenericBrowser("w3m"))
505 # Platform support for Windows
508 if sys
.platform
[:3] == "win":
509 class WindowsDefault(BaseBrowser
):
510 def open(self
, url
, new
=0, autoraise
=True):
514 # [Error 22] No application is associated with the specified
515 # file for this operation: '<URL>'
523 # First try to use the default Windows browser
524 register("windows-default", WindowsDefault
)
526 # Detect some common Windows browsers, fallback to IE
527 iexplore
= os
.path
.join(os
.environ
.get("PROGRAMFILES", "C:\\Program Files"),
528 "Internet Explorer\\IEXPLORE.EXE")
529 for browser
in ("firefox", "firebird", "seamonkey", "mozilla",
530 "netscape", "opera", iexplore
):
531 if _iscommand(browser
):
532 register(browser
, None, BackgroundBrowser(browser
))
535 # Platform support for MacOS
538 if sys
.platform
== 'darwin':
539 # Adapted from patch submitted to SourceForge by Steven J. Burr
540 class MacOSX(BaseBrowser
):
541 """Launcher class for Aqua browsers on Mac OS X
543 Optionally specify a browser name on instantiation. Note that this
544 will not work for Aqua browsers if the user has moved the application
545 package after installation.
547 If no browser is specified, the default browser, as specified in the
548 Internet System Preferences panel, will be used.
550 def __init__(self
, name
):
553 def open(self
, url
, new
=0, autoraise
=True):
554 assert "'" not in url
555 # hack for local urls
561 if self
.name
== "default":
562 # User called open, open_new or get without a browser parameter
563 script
= 'open location "%s"' % url
.replace('"', '%22') # opens in default browser
565 # User called get and chose a browser
566 if self
.name
== "OmniWeb":
569 # Include toWindow parameter of OpenURL command for browsers
570 # that support it. 0 == new window; -1 == existing
571 toWindow
= "toWindow %d" % (new
- 1)
572 cmd
= 'OpenURL "%s"' % url
.replace('"', '%22')
573 script
= '''tell application "%s"
576 end tell''' % (self
.name
, cmd
, toWindow
)
577 # Open pipe to AppleScript through osascript command
578 osapipe
= os
.popen("osascript", "w")
581 # Write script to osascript's stdin
582 osapipe
.write(script
)
586 class MacOSXOSAScript(BaseBrowser
):
587 def __init__(self
, name
):
590 def open(self
, url
, new
=0, autoraise
=True):
591 if self
._name
== 'default':
592 script
= 'open location "%s"' % url
.replace('"', '%22') # opens in default browser
595 tell application "%s"
599 '''%(self
._name
, url
.replace('"', '%22'))
601 osapipe
= os
.popen("osascript", "w")
605 osapipe
.write(script
)
610 # Don't clear _tryorder or _browsers since OS X can use above Unix support
611 # (but we prefer using the OS X specific stuff)
612 register("safari", None, MacOSXOSAScript('safari'), -1)
613 register("firefox", None, MacOSXOSAScript('firefox'), -1)
614 register("MacOSX", None, MacOSXOSAScript('default'), -1)
618 # Platform support for OS/2
621 if sys
.platform
[:3] == "os2" and _iscommand("netscape"):
624 register("os2netscape", None,
625 GenericBrowser(["start", "netscape", "%s"]), -1)
628 # OK, now that we know what the default preference orders for each
629 # platform are, allow user to override them with the BROWSER variable.
630 if "BROWSER" in os
.environ
:
631 _userchoices
= os
.environ
["BROWSER"].split(os
.pathsep
)
632 _userchoices
.reverse()
634 # Treat choices in same way as if passed into get() but do register
635 # and prepend to _tryorder
636 for cmdline
in _userchoices
:
638 cmd
= _synthesize(cmdline
, -1)
640 register(cmdline
, None, GenericBrowser(cmdline
), -1)
641 cmdline
= None # to make del work if _userchoices was empty
645 # what to do if _tryorder is now empty?
650 usage
= """Usage: %s [-n | -t] url
652 -t: open new tab""" % sys
.argv
[0]
654 opts
, args
= getopt
.getopt(sys
.argv
[1:], 'ntd')
655 except getopt
.error
, msg
:
656 print >>sys
.stderr
, msg
657 print >>sys
.stderr
, usage
661 if o
== '-n': new_win
= 1
662 elif o
== '-t': new_win
= 2
664 print >>sys
.stderr
, usage
672 if __name__
== "__main__":