From e280d6c2833c25867b8139490e68ddf056477917 Mon Sep 17 00:00:00 2001 From: Athanasius Date: Sat, 3 Dec 2022 18:17:51 +0000 Subject: [PATCH] ttkHyperlinklabel.py: Initial flake8 pass (and some mypy) This fixes an apparently harmless bug in the `openurl()` function defined in this module (it's not part of the class). 1. On `win32` lookup the user setting for opening HTTPS URLs. 2. If that doesn't look like IE or Edge... 3. Set `cls` to the value for that. 4. Now look up the 'use this command' for *that* ... 5. And if it doesn't have `iexplore` in it... 6. Use `subprocess.Popen()` to invoke that browser with the given URL. The problem is that step 6 still tries to use `buf.value`. But `buf` is no longer present as it was from before 5989acd0d3263e54429ff99769ff73a20476d863 changed over to `winreg`. It should be just `value` from the winreg calls. That exception is then caught and ignored, and it ends up just running `webbrowser.open(url)` anyway. To be honest, this feels like we should just make this an unconditional call to `webbrowser.open(url)` now, given apparently no-one's complained about it always actually using that not working for them. Given Edge is Chrome-based now, and any supported OS should have Edge, Chrome or Firefox (OK, maybe Safari and some others) as the HTTPS browser, I don't see this being an issue. --- ttkHyperlinkLabel.py | 66 +++++++++++++++++++++++++++++++------------- 1 file changed, 47 insertions(+), 19 deletions(-) diff --git a/ttkHyperlinkLabel.py b/ttkHyperlinkLabel.py index 8dd08644..5a13a5fc 100644 --- a/ttkHyperlinkLabel.py +++ b/ttkHyperlinkLabel.py @@ -1,7 +1,23 @@ +""" +A clickable ttk label for HTTP links. + +In addition to standard ttk.Label arguments, takes the following arguments: + url: The URL as a string that the user will be sent to on clicking on + non-empty label text. If url is a function it will be called on click with + the current label text and should return the URL as a string. + underline: If True/False the text is always/never underlined. If None (the + default) the text is underlined only on hover. + popup_copy: Whether right-click on non-empty label text pops up a context + menu with a 'Copy' option. Defaults to no context menu. If popup_copy is a + function it will be called with the current label text and should return a + boolean. + +May be imported by plugins +""" import sys import tkinter as tk import webbrowser -from tkinter import font as tkFont +from tkinter import font as tk_font from tkinter import ttk if sys.platform == 'win32': @@ -10,15 +26,10 @@ if sys.platform == 'win32': # A clickable ttk Label # -# In addition to standard ttk.Label arguments, takes the following arguments: -# url: The URL as a string that the user will be sent to on clicking on non-empty label text. If url is a function it will be called on click with the current label text and should return the URL as a string. -# underline: If True/False the text is always/never underlined. If None (the default) the text is underlined only on hover. -# popup_copy: Whether right-click on non-empty label text pops up a context menu with a 'Copy' option. Defaults to no context menu. If popup_copy is a function it will be called with the current label text and should return a boolean. -# -# May be imported by plugins class HyperlinkLabel(sys.platform == 'darwin' and tk.Label or ttk.Label, object): + """Clickable label for HTTP links.""" def __init__(self, master=None, **kw): self.url = 'url' in kw and kw.pop('url') or None @@ -51,8 +62,8 @@ class HyperlinkLabel(sys.platform == 'darwin' and tk.Label or ttk.Label, object) text=kw.get('text'), font=kw.get('font', ttk.Style().lookup('TLabel', 'font'))) - # Change cursor and appearance depending on state and text - def configure(self, cnf=None, **kw): + def configure(self, cnf=None, **kw): # noqa: CCR001 + """Change cursor and appearance depending on state and text.""" # This class' state for thing in ['url', 'popup_copy', 'underline']: if thing in kw: @@ -71,7 +82,7 @@ class HyperlinkLabel(sys.platform == 'darwin' and tk.Label or ttk.Label, object) if 'font' in kw: self.font_n = kw['font'] - self.font_u = tkFont.Font(font=self.font_n) + self.font_u = tk_font.Font(font=self.font_n) self.font_u.configure(underline=True) kw['font'] = self.underline is True and self.font_u or self.font_n @@ -86,7 +97,13 @@ class HyperlinkLabel(sys.platform == 'darwin' and tk.Label or ttk.Label, object) super(HyperlinkLabel, self).configure(cnf, **kw) - def __setitem__(self, key, value): + def __setitem__(self, key, value) -> None: + """ + Allow for dict member style setting of options. + + :param key: option name + :param value: option value + """ self.configure(None, **{key: value}) def _enter(self, event): @@ -108,17 +125,23 @@ class HyperlinkLabel(sys.platform == 'darwin' and tk.Label or ttk.Label, object) if self['text'] and (self.popup_copy(self['text']) if callable(self.popup_copy) else self.popup_copy): self.menu.post(sys.platform == 'darwin' and event.x_root + 1 or event.x_root, event.y_root) - def copy(self): + def copy(self) -> None: + """Copy the current text to the clipboard.""" self.clipboard_clear() self.clipboard_append(self['text']) -def openurl(url): +def openurl(url) -> None: # noqa: CCR001 + """ + Open the given URL in appropriate browser. + + :param url: URL to open. + """ if sys.platform == 'win32': + # FIXME: Is still still true with supported Windows 10 and 11 ? # On Windows webbrowser.open calls os.startfile which calls ShellExecute which can't handle long arguments, # so discover and launch the browser directly. # https://blogs.msdn.microsoft.com/oldnewthing/20031210-00/?p=41553 - try: hkey = OpenKeyEx(HKEY_CURRENT_USER, r'Software\Microsoft\Windows\Shell\Associations\UrlAssociations\https\UserChoice') @@ -128,23 +151,28 @@ def openurl(url): # IE and Edge can't handle long arguments so just use webbrowser.open and hope # https://blogs.msdn.microsoft.com/ieinternals/2014/08/13/url-length-limits/ cls = None + else: cls = value - except: + + except Exception: cls = 'https' if cls: try: - hkey = OpenKeyEx(HKEY_CLASSES_ROOT, r'%s\shell\open\command' % cls) + hkey = OpenKeyEx(HKEY_CLASSES_ROOT, rf'{cls}\shell\open\command') (value, typ) = QueryValueEx(hkey, None) CloseKey(hkey) if 'iexplore' not in value.lower(): if '%1' in value: - subprocess.Popen(buf.value.replace('%1', url)) + subprocess.Popen(value.replace('%1', url)) + else: - subprocess.Popen('%s "%s"' % (buf.value, url)) + subprocess.Popen(f'{value} "{url}"') + return - except: + + except Exception: pass webbrowser.open(url)