1111
1212__all__ = ["Error" , "open" , "open_new" , "open_new_tab" , "get" , "register" ]
1313
14+
1415class Error (Exception ):
1516 pass
1617
18+
1719_lock = threading .RLock ()
1820_browsers = {} # Dictionary of available browser controllers
1921_tryorder = None # Preference order of available browsers
2022_os_preferred_browser = None # The preferred browser
2123
24+
2225def register (name , klass , instance = None , * , preferred = False ):
2326 """Register a browser connector."""
2427 with _lock :
@@ -34,6 +37,7 @@ def register(name, klass, instance=None, *, preferred=False):
3437 else :
3538 _tryorder .append (name )
3639
40+
3741def get (using = None ):
3842 """Return a browser launcher instance appropriate for the environment."""
3943 if _tryorder is None :
@@ -64,6 +68,7 @@ def get(using=None):
6468 return command [0 ]()
6569 raise Error ("could not locate runnable browser" )
6670
71+
6772# Please note: the following definition hides a builtin function.
6873# It is recommended one does "import webbrowser" and uses webbrowser.open(url)
6974# instead of "from webbrowser import *".
@@ -87,13 +92,15 @@ def open(url, new=0, autoraise=True):
8792 return True
8893 return False
8994
95+
9096def open_new (url ):
9197 """Open url in a new window of the default browser.
9298
9399 If not possible, then open url in the only browser window.
94100 """
95101 return open (url , 1 )
96102
103+
97104def open_new_tab (url ):
98105 """Open url in a new page ("tab") of the default browser.
99106
@@ -136,7 +143,7 @@ def _synthesize(browser, *, preferred=False):
136143
137144# General parent classes
138145
139- class BaseBrowser ( object ) :
146+ class BaseBrowser :
140147 """Parent class for all browsers. Do not use directly."""
141148
142149 args = ['%s' ]
@@ -197,7 +204,7 @@ def open(self, url, new=0, autoraise=True):
197204 else :
198205 p = subprocess .Popen (cmdline , close_fds = True ,
199206 start_new_session = True )
200- return ( p .poll () is None )
207+ return p .poll () is None
201208 except OSError :
202209 return False
203210
@@ -225,7 +232,8 @@ def _invoke(self, args, remote, autoraise, url=None):
225232 # use autoraise argument only for remote invocation
226233 autoraise = int (autoraise )
227234 opt = self .raise_opts [autoraise ]
228- if opt : raise_opt = [opt ]
235+ if opt :
236+ raise_opt = [opt ]
229237
230238 cmdline = [self .name ] + raise_opt + args
231239
@@ -266,8 +274,8 @@ def open(self, url, new=0, autoraise=True):
266274 else :
267275 action = self .remote_action_newtab
268276 else :
269- raise Error ("Bad 'new' parameter to open(); " +
270- "expected 0, 1, or 2, got %s" % new )
277+ raise Error ("Bad 'new' parameter to open(); "
278+ f "expected 0, 1, or 2, got { new } " )
271279
272280 args = [arg .replace ("%s" , url ).replace ("%action" , action )
273281 for arg in self .remote_args ]
@@ -302,19 +310,20 @@ class Epiphany(UnixBrowser):
302310
303311
304312class Chrome (UnixBrowser ):
305- "Launcher class for Google Chrome browser."
313+ """ Launcher class for Google Chrome browser."" "
306314
307315 remote_args = ['%action' , '%s' ]
308316 remote_action = ""
309317 remote_action_newwin = "--new-window"
310318 remote_action_newtab = ""
311319 background = True
312320
321+
313322Chromium = Chrome
314323
315324
316325class Opera (UnixBrowser ):
317- "Launcher class for Opera browser."
326+ """ Launcher class for Opera browser."" "
318327
319328 remote_args = ['%action' , '%s' ]
320329 remote_action = ""
@@ -324,7 +333,7 @@ class Opera(UnixBrowser):
324333
325334
326335class Elinks (UnixBrowser ):
327- "Launcher class for Elinks browsers."
336+ """ Launcher class for Elinks browsers."" "
328337
329338 remote_args = ['-remote' , 'openURL(%s%action)' ]
330339 remote_action = ""
@@ -387,11 +396,11 @@ def open(self, url, new=0, autoraise=True):
387396 except OSError :
388397 return False
389398 else :
390- return ( p .poll () is None )
399+ return p .poll () is None
391400
392401
393402class Edge (UnixBrowser ):
394- "Launcher class for Microsoft Edge browser."
403+ """ Launcher class for Microsoft Edge browser."" "
395404
396405 remote_args = ['%action' , '%s' ]
397406 remote_action = ""
@@ -461,7 +470,6 @@ def register_X_browsers():
461470 if shutil .which ("opera" ):
462471 register ("opera" , None , Opera ("opera" ))
463472
464-
465473 if shutil .which ("microsoft-edge" ):
466474 register ("microsoft-edge" , None , Edge ("microsoft-edge" ))
467475
@@ -514,7 +522,8 @@ def register_standard_browsers():
514522 cmd = "xdg-settings get default-web-browser" .split ()
515523 raw_result = subprocess .check_output (cmd , stderr = subprocess .DEVNULL )
516524 result = raw_result .decode ().strip ()
517- except (FileNotFoundError , subprocess .CalledProcessError , PermissionError , NotADirectoryError ) :
525+ except (FileNotFoundError , subprocess .CalledProcessError ,
526+ PermissionError , NotADirectoryError ):
518527 pass
519528 else :
520529 global _os_preferred_browser
@@ -584,15 +593,16 @@ def __init__(self, name='default'):
584593
585594 def open (self , url , new = 0 , autoraise = True ):
586595 sys .audit ("webbrowser.open" , url )
596+ url = url .replace ('"' , '%22' )
587597 if self .name == 'default' :
588- script = 'open location "%s"' % url . replace ( '"' , '%22' ) # opens in default browser
598+ script = f 'open location "{ url } "' # opens in default browser
589599 else :
590600 script = f'''
591- tell application "%s "
601+ tell application "{ self . name } "
592602 activate
593- open location "%s "
603+ open location "{ url } "
594604 end
595- ''' % ( self . name , url . replace ( '"' , '%22' ))
605+ '''
596606
597607 osapipe = os .popen ("osascript" , "w" )
598608 if osapipe is None :
@@ -667,33 +677,31 @@ def open(self, url, new=0, autoraise=True):
667677 return True
668678
669679
670- def main ():
671- import getopt
672- usage = """Usage: %s [-n | -t | -h] url
673- -n: open new window
674- -t: open new tab
675- -h, --help: show help""" % sys .argv [0 ]
676- try :
677- opts , args = getopt .getopt (sys .argv [1 :], 'ntdh' ,['help' ])
678- except getopt .error as msg :
679- print (msg , file = sys .stderr )
680- print (usage , file = sys .stderr )
681- sys .exit (1 )
682- new_win = 0
683- for o , a in opts :
684- if o == '-n' : new_win = 1
685- elif o == '-t' : new_win = 2
686- elif o == '-h' or o == '--help' :
687- print (usage , file = sys .stderr )
688- sys .exit ()
689- if len (args ) != 1 :
690- print (usage , file = sys .stderr )
691- sys .exit (1 )
692-
693- url = args [0 ]
694- open (url , new_win )
680+ def parse_args (arg_list : list [str ] | None ):
681+ import argparse
682+ parser = argparse .ArgumentParser (description = "Open URL in a web browser." )
683+ parser .add_argument ("url" , help = "URL to open" )
684+
685+ group = parser .add_mutually_exclusive_group ()
686+ group .add_argument ("-n" , "--new-window" , action = "store_const" ,
687+ const = 1 , default = 0 , dest = "new_win" ,
688+ help = "open new window" )
689+ group .add_argument ("-t" , "--new-tab" , action = "store_const" ,
690+ const = 2 , default = 0 , dest = "new_win" ,
691+ help = "open new tab" )
692+
693+ args = parser .parse_args (arg_list )
694+
695+ return args
696+
697+
698+ def main (arg_list : list [str ] | None = None ):
699+ args = parse_args (arg_list )
700+
701+ open (args .url , args .new_win )
695702
696703 print ("\a " )
697704
705+
698706if __name__ == "__main__" :
699707 main ()
0 commit comments