Files
anki/docs-site/addons/monkey-patching.mdx
Andrew Sanchez fb0215a2c1 Prototype unified Mintlify docs site (#4882)
## Summary

- add a generated `docs-site/` Mintlify proof of concept for a unified
Anki docs site
- migrate the desktop manual, AnkiMobile docs, FAQs, add-on docs,
translation docs, release notes, legacy docs, and repo-local Sphinx/MyST
developer docs into the POC tree
- add a migration helper that preserves mdBook ordering, handles common
MDX incompatibilities, and regenerates the landing-page-inspired
Mintlify styling
- apply minimal styling based on the current Anki landing page: Anki
logo, Hanken Grotesk, blue primary color, subtle surfaces, and compact
nav treatment

## Validation

- `uv run --with ty ty check tools/mintlify_poc_migrate.py`
- `source ~/.nvm/nvm.sh && nvm use 22.15.0 && mint validate`
- previewed locally with `mint dev --port 3000` and checked the home
page/developer docs in browser

## Notes

This is intentionally a draft POC. It does not remove the existing
Sphinx or mdBook docs flows yet; it demonstrates what bringing the
sources into this repo and building from a single Mintlify root could
look like.

---------

Co-authored-by: Andrew Sanchez <andrewsanchez@users.noreply.github.com>
Co-authored-by: Luc Mcgrady <lucmcgrady@gmail.com>
Co-authored-by: Abdo <abdo@abdnh.net>
2026-06-12 16:27:33 +03:00

98 lines
3.1 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: "Monkey Patching and Method Wrapping"
---
If you want to modify a function that doesnt already have a hook, its
possible to overwrite that function with a custom version instead. This
is sometimes referred to as 'monkey patching'.
Monkey patching is useful in the testing stage, and while waiting for
new hooks to be integrated into Anki. But please dont rely on it long
term, as monkey patching is very fragile, and will tend to break as Anki
is updated in the future.
The only exception to the above is if youre making extensive changes to
Anki where adding new hooks would be impractical. In that case, you may
unfortunately need to modify your add-on periodically as Anki is
updated.
In
[aqt/editor.py](https://github.com/ankitects/anki/blob/main/qt/aqt/editor.py)
there is a function setupButtons() which creates the buttons like
bold, italics and so on that you see in the editor. Lets imagine you
want to add another button in your add-on.
Anki 2.1 no longer uses setupButtons(). The code below is still useful
to understand how monkey patching works, but for adding buttons to the
editor please see the setupEditorButtons hook described in the previous
section.
The simplest way is to copy and paste the function from the Anki source
code, add your text to the bottom, and then overwrite the original, like
so:
```python
from aqt.editor import Editor
def mySetupButtons(self):
<copy & pasted code from original>
<custom add-on code>
Editor.setupButtons = mySetupButtons
```
This approach is fragile however, as if the original code is updated in
a future version of Anki, you would also have to update your add-on. A
better approach would be to save the original, and call it in our custom
version:
```python
from aqt.editor import Editor
def mySetupButtons(self):
origSetupButtons(self)
<custom add-on code>
origSetupButtons = Editor.setupButtons
Editor.setupButtons = mySetupButtons
```
Because this is a common operation, Anki provides a function called
wrap() which makes this a little more convenient. A real example:
```python
from anki.hooks import wrap
from aqt.editor import Editor
from aqt.utils import showInfo
def buttonPressed(self):
showInfo("pressed " + `self`)
def mySetupButtons(self):
# - size=False tells Anki not to use a small button
# - the lambda is necessary to pass the editor instance to the
# callback, as we're passing in a function rather than a bound
# method
self._addButton("mybutton", lambda s=self: buttonPressed(self),
text="PressMe", size=False)
Editor.setupButtons = wrap(Editor.setupButtons, mySetupButtons)
```
By default, wrap() runs your custom code after the original code. You
can pass a third argument, "before", to reverse this. If you need to run
code both before and after the original version, you can do so like so:
```python
from anki.hooks import wrap
from aqt.editor import Editor
def mySetupButtons(self, _old):
<before code>
ret = _old(self)
<after code>
return ret
Editor.setupButtons = wrap(Editor.setupButtons, mySetupButtons, "around")
```