aqt.addons
==========

.. py:module:: aqt.addons


Attributes
----------

.. autoapisummary::

   aqt.addons.DownloadLogEntry
   aqt.addons.ANKIWEB_ID_RE


Exceptions
----------

.. autoapisummary::

   aqt.addons.AbortAddonImport


Classes
-------

.. autoapisummary::

   aqt.addons.InstallOk
   aqt.addons.InstallError
   aqt.addons.DownloadOk
   aqt.addons.DownloadError
   aqt.addons.AddonMeta
   aqt.addons.AddonManager
   aqt.addons.AddonsDialog
   aqt.addons.GetAddons
   aqt.addons.ExtractedDownloadMeta
   aqt.addons.DownloaderInstaller
   aqt.addons.ChooseAddonsToUpdateList
   aqt.addons.ChooseAddonsToUpdateDialog
   aqt.addons.ConfigEditor


Functions
---------

.. autoapisummary::

   aqt.addons.package_name_valid
   aqt.addons.download_addon
   aqt.addons.extract_meta_from_download_url
   aqt.addons.download_log_to_html
   aqt.addons.describe_log_entry
   aqt.addons.download_encountered_problem
   aqt.addons.download_and_install_addon
   aqt.addons.show_log_to_user
   aqt.addons.download_addons
   aqt.addons.fetch_update_info
   aqt.addons.check_and_prompt_for_updates
   aqt.addons.check_for_updates
   aqt.addons.handle_update_info
   aqt.addons.prompt_to_update
   aqt.addons.install_or_update_addon
   aqt.addons.installAddonPackages


Module Contents
---------------

.. py:exception:: AbortAddonImport

   Bases: :py:obj:`Exception`


   If raised during add-on import, Anki will silently ignore this exception.
   This allows you to terminate loading without an error being shown.


.. py:class:: InstallOk

   .. py:attribute:: name
      :type:  str


   .. py:attribute:: conflicts
      :type:  set[str]


   .. py:attribute:: compatible
      :type:  bool


.. py:class:: InstallError

   .. py:attribute:: errmsg
      :type:  str


.. py:class:: DownloadOk

   .. py:attribute:: data
      :type:  bytes


   .. py:attribute:: filename
      :type:  str


   .. py:attribute:: mod_time
      :type:  int


   .. py:attribute:: min_point_version
      :type:  int


   .. py:attribute:: max_point_version
      :type:  int


   .. py:attribute:: branch_index
      :type:  int


.. py:class:: DownloadError

   .. py:attribute:: status_code
      :type:  int | None
      :value: None



   .. py:attribute:: exception
      :type:  Exception | None
      :value: None



.. py:data:: DownloadLogEntry

.. py:data:: ANKIWEB_ID_RE

.. py:class:: AddonMeta

   .. py:attribute:: dir_name
      :type:  str


   .. py:attribute:: provided_name
      :type:  str | None


   .. py:attribute:: enabled
      :type:  bool


   .. py:attribute:: installed_at
      :type:  int


   .. py:attribute:: conflicts
      :type:  list[str]


   .. py:attribute:: min_version
      :type:  int


   .. py:attribute:: max_version
      :type:  int


   .. py:attribute:: branch_index
      :type:  int


   .. py:attribute:: human_version
      :type:  str | None


   .. py:attribute:: update_enabled
      :type:  bool


   .. py:attribute:: homepage
      :type:  str | None


   .. py:method:: human_name() -> str


   .. py:method:: ankiweb_id() -> int | None


   .. py:method:: compatible() -> bool


   .. py:method:: is_latest(server_update_time: int) -> bool


   .. py:method:: page() -> str | None


   .. py:method:: from_json_meta(dir_name: str, json_meta: dict[str, Any]) -> AddonMeta
      :staticmethod:



.. py:function:: package_name_valid(name: str) -> bool

.. py:class:: AddonManager(mw: aqt.main.AnkiQt)

   .. py:attribute:: exts
      :type:  list[str]
      :value: ['.ankiaddon', '.zip']



   .. py:attribute:: mw


   .. py:attribute:: dirty
      :value: False



   .. py:method:: allAddons() -> list[str]


   .. py:method:: all_addon_meta() -> collections.abc.Iterable[AddonMeta]


   .. py:method:: addonsFolder(module: str | None = None) -> str


   .. py:method:: loadAddons() -> None


   .. py:method:: onAddonsDialog() -> None


   .. py:method:: addon_meta(dir_name: str) -> AddonMeta

      Get info about an installed add-on.



   .. py:method:: write_addon_meta(addon: AddonMeta) -> None


   .. py:method:: addonMeta(module: str) -> dict[str, Any]


   .. py:method:: writeAddonMeta(module: str, meta: dict[str, Any]) -> None


   .. py:method:: toggleEnabled(module: str, enable: bool | None = None) -> None


   .. py:method:: ankiweb_addons() -> list[int]


   .. py:method:: isEnabled(module: str) -> bool


   .. py:method:: addonName(module: str) -> str


   .. py:method:: addonConflicts(module: str) -> list[str]


   .. py:method:: annotatedName(module: str) -> str


   .. py:method:: allAddonConflicts() -> dict[str, list[str]]


   .. py:method:: readManifestFile(zfile: zipfile.ZipFile) -> dict[Any, Any]


   .. py:method:: install(file: IO | str, manifest: dict[str, Any] | None = None, force_enable: bool = False) -> InstallOk | InstallError

      Install add-on from path or file-like object. Metadata is read
      from the manifest file, with keys overridden by supplying a 'manifest'
      dictionary



   .. py:method:: deleteAddon(module: str) -> None


   .. py:method:: processPackages(paths: list[str], parent: QWidget | None = None, force_enable: bool = False) -> tuple[list[str], list[str]]


   .. py:method:: update_supported_versions(items: list[anki.collection.AddonInfo]) -> None

      Adjust the supported version range after an update check.

      AnkiWeb will not have sent us any add-ons that don't support our
      version, so this cannot disable add-ons that users are using. It
      does allow the add-on author to mark an add-on as not supporting
      a future release, causing the add-on to be disabled when the user
      upgrades.



   .. py:method:: get_updated_addons(items: list[anki.collection.AddonInfo]) -> list[anki.collection.AddonInfo]

      Return ids of add-ons requiring an update.



   .. py:method:: addonConfigDefaults(module: str) -> dict[str, Any] | None


   .. py:method:: set_config_help_action(module: str, action: collections.abc.Callable[[], str]) -> None

      Set a callback used to produce config help.



   .. py:method:: addonConfigHelp(module: str) -> str


   .. py:method:: addonFromModule(module: str) -> str


   .. py:method:: addon_from_module(module: str) -> str
      :staticmethod:



   .. py:method:: configAction(module: str) -> collections.abc.Callable[[], bool | None]


   .. py:method:: configUpdatedAction(module: str) -> collections.abc.Callable[[Any], None]


   .. py:method:: getConfig(module: str) -> dict[str, Any] | None


   .. py:method:: setConfigAction(module: str, fn: collections.abc.Callable[[], bool | None]) -> None


   .. py:method:: setConfigUpdatedAction(module: str, fn: collections.abc.Callable[[Any], None]) -> None


   .. py:method:: writeConfig(module: str, conf: dict) -> None


   .. py:method:: backupUserFiles(module: str) -> None


   .. py:method:: restoreUserFiles(sid: str) -> None


   .. py:method:: setWebExports(module: str, pattern: str) -> None


   .. py:method:: getWebExports(module: str) -> str


   .. py:method:: get_logger(module: str) -> logging.Logger
      :classmethod:


      Return a logger for the given add-on module.

      NOTE: This method is static to allow it to be called outside of a
      running Anki instance, e.g. in add-on unit tests.



   .. py:method:: has_logger(module: str) -> bool


   .. py:method:: is_debug_logging_enabled(module: str) -> bool


   .. py:method:: toggle_debug_logging(module: str, enable: bool) -> None


   .. py:method:: logs_folder(module: str) -> pathlib.Path


.. py:class:: AddonsDialog(addonsManager: AddonManager)

   Bases: :py:obj:`QDialog`


   .. py:attribute:: mgr


   .. py:attribute:: mw


   .. py:method:: dragEnterEvent(event: QDragEnterEvent) -> None


   .. py:method:: dropEvent(event: QDropEvent) -> None


   .. py:method:: reject() -> None


   .. py:attribute:: silentlyClose
      :value: True



   .. py:method:: name_for_addon_list(addon: AddonMeta) -> str


   .. py:method:: compatible_string(addon: AddonMeta) -> str


   .. py:method:: should_grey(addon: AddonMeta) -> bool


   .. py:method:: redrawAddons() -> None


   .. py:method:: selectedAddons() -> list[str]


   .. py:method:: onlyOneSelected() -> str | None


   .. py:method:: selected_addon_meta() -> AddonMeta | None


   .. py:method:: onToggleEnabled() -> None


   .. py:method:: onViewPage() -> None


   .. py:method:: onViewFiles() -> None


   .. py:method:: onDelete() -> None


   .. py:method:: onGetAddons() -> None


   .. py:method:: after_downloading(log: list[DownloadLogEntry]) -> None


   .. py:method:: onInstallFiles(paths: list[str] | None = None) -> bool | None


   .. py:method:: check_for_updates() -> None


   .. py:method:: onConfig() -> None


.. py:class:: GetAddons(dlg: AddonsDialog)

   Bases: :py:obj:`QDialog`


   .. py:attribute:: addonsDlg


   .. py:attribute:: mgr


   .. py:attribute:: mw


   .. py:attribute:: ids
      :type:  list[int]
      :value: []



   .. py:attribute:: form


   .. py:method:: onBrowse() -> None


   .. py:method:: accept() -> None


.. py:function:: download_addon(client: anki.httpclient.HttpClient, id: int) -> DownloadOk | DownloadError

   Fetch a single add-on from AnkiWeb.


.. py:class:: ExtractedDownloadMeta

   .. py:attribute:: mod_time
      :type:  int


   .. py:attribute:: min_point_version
      :type:  int


   .. py:attribute:: max_point_version
      :type:  int


   .. py:attribute:: branch_index
      :type:  int


.. py:function:: extract_meta_from_download_url(url: str) -> ExtractedDownloadMeta

.. py:function:: download_log_to_html(log: list[DownloadLogEntry]) -> str

.. py:function:: describe_log_entry(id_and_entry: DownloadLogEntry) -> str

.. py:function:: download_encountered_problem(log: list[DownloadLogEntry]) -> bool

.. py:function:: download_and_install_addon(mgr: AddonManager, client: anki.httpclient.HttpClient, id: int, force_enable: bool = False) -> DownloadLogEntry

   Download and install a single add-on.


.. py:class:: DownloaderInstaller(parent: QWidget, mgr: AddonManager, client: anki.httpclient.HttpClient)

   Bases: :py:obj:`QObject`


   .. py:attribute:: progressSignal


   .. py:attribute:: mgr


   .. py:attribute:: client


   .. py:method:: download(ids: list[int], on_done: collections.abc.Callable[[list[DownloadLogEntry]], None], force_enable: bool = False) -> None


.. py:function:: show_log_to_user(parent: QWidget, log: list[DownloadLogEntry], title: str = 'Anki') -> None

.. py:function:: download_addons(parent: QWidget, mgr: AddonManager, ids: list[int], on_done: collections.abc.Callable[[list[DownloadLogEntry]], None], client: anki.httpclient.HttpClient | None = None, force_enable: bool = False) -> None

.. py:class:: ChooseAddonsToUpdateList(parent: QWidget, mgr: AddonManager, updated_addons: list[anki.collection.AddonInfo])

   Bases: :py:obj:`QListWidget`


   .. py:attribute:: ADDON_ID_ROLE
      :value: 101



   .. py:attribute:: mgr


   .. py:attribute:: updated_addons


   .. py:attribute:: ignore_check_evt
      :value: False



   .. py:method:: setup() -> None


   .. py:method:: bool_to_check(check_bool: bool) -> Qt.CheckState


   .. py:method:: checked(item: QListWidgetItem) -> bool


   .. py:method:: on_click(item: QListWidgetItem) -> None


   .. py:method:: on_check(item: QListWidgetItem) -> None


   .. py:method:: on_double_click(item: QListWidgetItem) -> None


   .. py:method:: on_context_menu(point: QPoint) -> None


   .. py:method:: check_item(item: QListWidgetItem, check: Qt.CheckState) -> None

      call item.setCheckState without triggering on_check



   .. py:method:: header_checked(check: Qt.CheckState) -> None


   .. py:method:: refresh_header_check_state() -> None


   .. py:method:: get_selected_addon_ids() -> list[int]


   .. py:method:: save_check_state() -> None


.. py:class:: ChooseAddonsToUpdateDialog(parent: QWidget, mgr: AddonManager, updated_addons: list[anki.collection.AddonInfo])

   Bases: :py:obj:`QDialog`


   .. py:attribute:: mgr


   .. py:attribute:: updated_addons


   .. py:method:: setup() -> None


   .. py:method:: ask(on_done: collections.abc.Callable[[list[int]], None]) -> None


   .. py:method:: accept() -> None


.. py:function:: fetch_update_info(ids: list[int]) -> list[anki.collection.AddonInfo]

   Fetch update info from AnkiWeb in one or more batches.


.. py:function:: check_and_prompt_for_updates(parent: QWidget, mgr: AddonManager, on_done: collections.abc.Callable[[list[DownloadLogEntry]], None], requested_by_user: bool = True) -> None

.. py:function:: check_for_updates(mgr: AddonManager, on_done: collections.abc.Callable[[list[anki.collection.AddonInfo]], None]) -> None

.. py:function:: handle_update_info(parent: QWidget, mgr: AddonManager, items: list[anki.collection.AddonInfo], on_done: collections.abc.Callable[[list[DownloadLogEntry]], None], requested_by_user: bool = True) -> None

.. py:function:: prompt_to_update(parent: QWidget, mgr: AddonManager, updated_addons: list[anki.collection.AddonInfo], on_done: collections.abc.Callable[[list[DownloadLogEntry]], None], requested_by_user: bool = True) -> None

.. py:function:: install_or_update_addon(parent: QWidget, mgr: AddonManager, addon_id: int, on_done: collections.abc.Callable[[list[DownloadLogEntry]], None]) -> None

.. py:class:: ConfigEditor(dlg: AddonsDialog, addon: str, conf: dict)

   Bases: :py:obj:`QDialog`


   .. py:attribute:: addon


   .. py:attribute:: conf


   .. py:attribute:: mgr


   .. py:attribute:: form


   .. py:method:: onRestoreDefaults() -> None


   .. py:method:: setupFonts() -> None


   .. py:method:: updateHelp() -> None


   .. py:method:: updateText(conf: dict[str, Any]) -> None


   .. py:method:: onClose() -> None


   .. py:method:: reject() -> None


   .. py:method:: accept() -> None


.. py:function:: installAddonPackages(addonsManager: AddonManager, paths: list[str], parent: QWidget | None = None, warn: bool = False, strictly_modal: bool = False, advise_restart: bool = False, force_enable: bool = False) -> bool

