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