External help links for `aqt.utils.showInfo()`

I am using showCritical() for displaying an error in my add-on. I would like to pass an absolute URL like the URL of the GitHub issues page as the help argument. But it is always interpreted as a relative URL to the Anki docs site, for example.

I understand that there may be concerns that Anki opens arbitrary URLs but:

  1. An add-on can probably even open the browser itself, right?
  2. It would be possible to restrict the domain name part to a number of domains like the Anki forums, GitHub, …

Any chance to get that implemented?

I recommend just copying the function’s code to your add-on and modifying it.

1 Like

Good idea! I will try that.

Still, wouldn’t it make sense to incorporate that into showInfo() instead of forcing copy and paste?

1 Like

It is actually simpler than that. You can pass custom buttons to showInfo() and friends. I will post a code sample here, when I’m done.

As it turned out, passing a customBtn argument to showInfo() does not help because you cannot connect a signal to the buttons.

You have to roll your own version. The code below shows how to format a Python exception and display it in the message box. Clicking the help button will open the external help URL in the user’s default browser:

import html
import traceback

from aqt import mw, qconnect
from aqt.qt import (QDialog, Qt, QMessageBox, # type: ignore[attr-defined]
					QDesktopServices, QUrl) # type: ignore[attr-defined]
from anki.utils import no_bundled_libs


class MyDialog(QDialog):


	def __init__(self):
		super().__init__()
		# Dialog design goes here.

	def accept(self) -> None:
		try:
			raise TypeError('I cannot type!')
		except Exception as e:
			self._show_exception(e)

	def _show_exception(self, e: Exception):
		ftb = list(traceback.format_tb(e.__traceback__))

		msgs = (
			_('An error occurred!'),
			_('Clicking the help button will open a web page explaining how to report a bug.'),
			_('Please include the following information in your bug report:'),
			_('<hr />'),
			_('Exception type:') + ' ' + html.escape(type(e).__name__),
			_('Exception message:') + ' ' + html.escape(str(e)),
			_('Traceback:'),
		)
		msg = '<br />'.join(msgs) + '<br  />'.join(ftb)
		print(msg)

		parent = mw.app.activeWindow() or mw
		msg_box = QMessageBox(parent)
		msg_box.setIcon(QMessageBox.Icon.Critical)
		msg_box.setTextFormat(Qt.TextFormat.MarkdownText)
		msg_box.setText(msg)
		msg_box.setWindowTitle(_('Chess Opening Trainer'))

		# This is the reason, whey the customBtn argument for `showInfo()`
		# cannot be used.  You can only call setDefault() or use
		# qconnect() with the return value of addButton() which is a
		# pointer to QPushButton.
		ok_button = msg_box.addButton(QMessageBox.StandardButton.Ok)
		ok_button.setDefault(True)

		def open_link(link: str):
			with no_bundled_libs():
				QDesktopServices.openUrl(QUrl(link))

		help_button = msg_box.addButton(QMessageBox.StandardButton.Help)
		link = _('https://www.guido-flohr.net/practice-chess-openings-with-anki/#report-bugs')
		help_button.clicked = qconnect(
			help_button.clicked,
			lambda: open_link(link),
		)
		help_button.setAutoDefault(False)

		return msg_box.exec()