anki.collection
===============

.. py:module:: anki.collection


Attributes
----------

.. autoapisummary::

   anki.collection.HelpPage
   anki.collection.SearchNode
   anki.collection.Progress
   anki.collection.EmptyCardsReport
   anki.collection.GraphPreferences
   anki.collection.CardStats
   anki.collection.Preferences
   anki.collection.UndoStatus
   anki.collection.OpChanges
   anki.collection.OpChangesOnly
   anki.collection.OpChangesWithCount
   anki.collection.OpChangesWithId
   anki.collection.OpChangesAfterUndo
   anki.collection.BrowserRow
   anki.collection.BrowserColumns
   anki.collection.StripHtmlMode
   anki.collection.ImportLogWithChanges
   anki.collection.ImportAnkiPackageRequest
   anki.collection.ImportAnkiPackageOptions
   anki.collection.ExportAnkiPackageOptions
   anki.collection.ImportCsvRequest
   anki.collection.CsvMetadata
   anki.collection.DupeResolution
   anki.collection.Delimiter
   anki.collection.TtsVoice
   anki.collection.GetImageForOcclusionResponse
   anki.collection.AddImageOcclusionNoteRequest
   anki.collection.GetImageOcclusionNoteResponse
   anki.collection.AddonInfo
   anki.collection.CheckForUpdateResponse
   anki.collection.MediaSyncStatus
   anki.collection.FsrsItem
   anki.collection.FsrsReview
   anki.collection.SearchJoiner
   anki.collection.ExportLimit


Classes
-------

.. autoapisummary::

   anki.collection.DeckIdLimit
   anki.collection.NoteIdsLimit
   anki.collection.CardIdsLimit
   anki.collection.ComputedMemoryState
   anki.collection.AddNoteRequest
   anki.collection.Collection


Functions
---------

.. autoapisummary::

   anki.collection.pb_export_limit


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

.. py:data:: HelpPage

.. py:data:: SearchNode

.. py:data:: Progress

.. py:data:: EmptyCardsReport

.. py:data:: GraphPreferences

.. py:data:: CardStats

.. py:data:: Preferences

.. py:data:: UndoStatus

.. py:data:: OpChanges

.. py:data:: OpChangesOnly

.. py:data:: OpChangesWithCount

.. py:data:: OpChangesWithId

.. py:data:: OpChangesAfterUndo

.. py:data:: BrowserRow

.. py:data:: BrowserColumns

.. py:data:: StripHtmlMode

.. py:data:: ImportLogWithChanges

.. py:data:: ImportAnkiPackageRequest

.. py:data:: ImportAnkiPackageOptions

.. py:data:: ExportAnkiPackageOptions

.. py:data:: ImportCsvRequest

.. py:data:: CsvMetadata

.. py:data:: DupeResolution

.. py:data:: Delimiter

.. py:data:: TtsVoice

.. py:data:: GetImageForOcclusionResponse

.. py:data:: AddImageOcclusionNoteRequest

.. py:data:: GetImageOcclusionNoteResponse

.. py:data:: AddonInfo

.. py:data:: CheckForUpdateResponse

.. py:data:: MediaSyncStatus

.. py:data:: FsrsItem

.. py:data:: FsrsReview

.. py:data:: SearchJoiner

.. py:class:: DeckIdLimit

   .. py:attribute:: deck_id
      :type:  anki.decks.DeckId


.. py:class:: NoteIdsLimit

   .. py:attribute:: note_ids
      :type:  collections.abc.Sequence[anki.notes.NoteId]


.. py:class:: CardIdsLimit

   .. py:attribute:: card_ids
      :type:  collections.abc.Sequence[anki.cards.CardId]


.. py:data:: ExportLimit

.. py:class:: ComputedMemoryState

   .. py:attribute:: desired_retention
      :type:  float


   .. py:attribute:: stability
      :type:  float | None
      :value: None



   .. py:attribute:: difficulty
      :type:  float | None
      :value: None



   .. py:attribute:: decay
      :type:  float | None
      :value: None



.. py:class:: AddNoteRequest

   .. py:attribute:: note
      :type:  anki.notes.Note


   .. py:attribute:: deck_id
      :type:  anki.decks.DeckId


.. py:class:: Collection(path: str, backend: anki._backend.RustBackend | None = None, server: bool = False)

   Bases: :py:obj:`anki._legacy.DeprecatedNamesMixin`


   .. py:attribute:: sched
      :type:  anki.scheduler.v3.Scheduler | anki.scheduler.dummy.DummyScheduler


   .. py:method:: initialize_backend_logging() -> None
      :staticmethod:


      Enable terminal logging. Must be called only once.



   .. py:attribute:: db
      :type:  anki.dbproxy.DBProxy | None
      :value: None



   .. py:attribute:: server
      :value: False



   .. py:attribute:: path
      :value: b'.'



   .. py:attribute:: tr


   .. py:attribute:: media


   .. py:attribute:: models


   .. py:attribute:: decks


   .. py:attribute:: tags


   .. py:attribute:: conf


   .. py:method:: name() -> Any


   .. py:method:: weakref() -> Collection

      Shortcut to create a weak reference that doesn't break code completion.



   .. py:property:: backend
      :type: anki._backend.RustBackend



   .. py:method:: format_timespan(seconds: float, context: anki.lang.FormatTimeSpan.Context.V = FormatTimeSpan.INTERVALS) -> str


   .. py:method:: latest_progress() -> Progress


   .. py:method:: sched_ver() -> Literal[1, 2]

      For backwards compatibility, the v3 scheduler currently returns 2.
      Use the separate v3_scheduler() method to check if it is active.



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


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


   .. py:method:: set_v3_scheduler(enabled: bool) -> None


   .. py:property:: crt
      :type: int



   .. py:property:: mod
      :type: int



   .. py:method:: save(**args: Any) -> None


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


   .. py:method:: close(downgrade: bool = False) -> None

      Disconnect from DB.



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


   .. py:method:: reopen(after_full_sync: bool = False) -> None


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


   .. py:method:: mod_schema(check: bool) -> None

      Mark schema modified. GUI catches this and will ask user if required.



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

      True if schema changed since last sync.



   .. py:method:: usn() -> int


   .. py:method:: create_backup(*, backup_folder: str, force: bool, wait_for_completion: bool) -> bool

      Create a backup if enough time has elapsed, and rotate old backups.

      If `force` is true, the user's configured backup interval is ignored.
      Returns true if backup created. This may be false in the force=True case,
      if no changes have been made to the collection.

      Throws on failure of current backup, or the previous backup if it was not
      awaited.



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

      Throws if backup creation failed.



   .. py:method:: export_collection_package(out_path: str, include_media: bool, legacy: bool) -> None


   .. py:method:: import_anki_package(request: ImportAnkiPackageRequest) -> ImportLogWithChanges


   .. py:method:: export_anki_package(*, out_path: str, options: ExportAnkiPackageOptions, limit: ExportLimit) -> int


   .. py:method:: get_csv_metadata(path: str, delimiter: Delimiter | None) -> CsvMetadata


   .. py:method:: import_csv(request: ImportCsvRequest) -> ImportLogWithChanges


   .. py:method:: export_note_csv(*, out_path: str, limit: ExportLimit, with_html: bool, with_tags: bool, with_deck: bool, with_notetype: bool, with_guid: bool) -> int


   .. py:method:: export_card_csv(*, out_path: str, limit: ExportLimit, with_html: bool) -> int


   .. py:method:: import_json_file(path: str) -> ImportLogWithChanges


   .. py:method:: import_json_string(json: str) -> ImportLogWithChanges


   .. py:method:: export_dataset_for_research(target_path: str, min_entries: int = 0) -> None


   .. py:method:: get_image_for_occlusion(path: str | None) -> GetImageForOcclusionResponse


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

      Add notetype if missing.



   .. py:method:: add_image_occlusion_note(notetype_id: int, image_path: str, occlusions: str, header: str, back_extra: str, tags: list[str]) -> OpChanges


   .. py:method:: get_image_occlusion_note(note_id: int | None) -> GetImageOcclusionNoteResponse


   .. py:method:: update_image_occlusion_note(note_id: int | None, occlusions: str | None, header: str | None, back_extra: str | None, tags: list[str] | None) -> OpChanges


   .. py:method:: get_card(id: anki.cards.CardId | None) -> anki.cards.Card


   .. py:method:: update_cards(cards: collections.abc.Sequence[anki.cards.Card], skip_undo_entry: bool = False) -> OpChanges

      Save card changes to database.



   .. py:method:: update_card(card: anki.cards.Card, skip_undo_entry: bool = False) -> OpChanges

      Save card changes to database.



   .. py:method:: get_note(id: anki.notes.NoteId) -> anki.notes.Note


   .. py:method:: update_notes(notes: collections.abc.Sequence[anki.notes.Note], skip_undo_entry: bool = False) -> OpChanges

      Save note changes to database.



   .. py:method:: update_note(note: anki.notes.Note, skip_undo_entry: bool = False) -> OpChanges

      Save note changes to database.



   .. py:method:: nextID(type: str, inc: bool = True) -> Any


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


   .. py:method:: new_note(notetype: anki.models.NotetypeDict) -> anki.notes.Note


   .. py:method:: add_note(note: anki.notes.Note, deck_id: anki.decks.DeckId) -> OpChangesWithCount


   .. py:method:: add_notes(requests: collections.abc.Iterable[AddNoteRequest]) -> OpChanges


   .. py:method:: remove_notes(note_ids: collections.abc.Sequence[anki.notes.NoteId]) -> OpChangesWithCount


   .. py:method:: remove_notes_by_card(card_ids: list[anki.cards.CardId]) -> None


   .. py:method:: card_ids_of_note(note_id: anki.notes.NoteId) -> collections.abc.Sequence[anki.cards.CardId]


   .. py:method:: defaults_for_adding(*, current_review_card: anki.cards.Card | None) -> anki.notes.DefaultsForAdding

      Get starting deck and notetype for add screen.
      An option in the preferences controls whether this will be based on the current deck
      or current notetype.



   .. py:method:: default_deck_for_notetype(notetype_id: anki.models.NotetypeId) -> anki.decks.DeckId | None

      If 'change deck depending on notetype' is enabled in the preferences,
      return the last deck used with the provided notetype, if any..



   .. py:method:: note_count() -> int


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


   .. py:method:: card_count() -> Any


   .. py:method:: remove_cards_and_orphaned_notes(card_ids: collections.abc.Sequence[anki.cards.CardId]) -> OpChangesWithCount

      You probably want .remove_notes_by_card() instead.



   .. py:method:: set_deck(card_ids: collections.abc.Sequence[anki.cards.CardId], deck_id: int) -> OpChangesWithCount


   .. py:method:: get_empty_cards() -> EmptyCardsReport


   .. py:method:: after_note_updates(nids: list[anki.notes.NoteId], mark_modified: bool, generate_cards: bool = True) -> None

      If notes modified directly in database, call this afterwards.



   .. py:method:: find_cards(query: str, order: bool | str | BrowserColumns = False, reverse: bool = False) -> collections.abc.Sequence[anki.cards.CardId]

      Return card ids matching the provided search.

      To programmatically construct a search string, see .build_search_string().

      If order=True, use the sort order stored in the collection config
      If order=False, do no ordering

      If order is a string, that text is added after 'order by' in the sql statement.
      You must add ' asc' or ' desc' to the order, as Anki will replace asc with
      desc and vice versa when reverse is set in the collection config, eg
      order="c.ivl asc, c.due desc".

      If order is a BrowserColumns.Column that supports sorting, sort using that
      column. All available columns are available through col.all_browser_columns()
      or browser.table._model.columns and support sorting cards unless column.sorting_cards
      is set to BrowserColumns.SORTING_NONE, .SORTING_NOTES_ASCENDING, or
      .SORTING_NOTES_DESCENDING.

      The reverse argument only applies when a BrowserColumns.Column is provided;
      otherwise the collection config defines whether reverse is set or not.



   .. py:method:: find_notes(query: str, order: bool | str | BrowserColumns = False, reverse: bool = False) -> collections.abc.Sequence[anki.notes.NoteId]

      Return note ids matching the provided search.

      To programmatically construct a search string, see .build_search_string().
      The order parameter is documented in .find_cards().



   .. py:method:: find_and_replace(*, note_ids: collections.abc.Sequence[anki.notes.NoteId], search: str, replacement: str, regex: bool = False, field_name: str | None = None, match_case: bool = False) -> OpChangesWithCount

      Find and replace fields in a note. Returns changed note count.



   .. py:method:: field_names_for_note_ids(nids: collections.abc.Sequence[int]) -> collections.abc.Sequence[str]


   .. py:method:: find_dupes(field_name: str, search: str = '') -> list[tuple[str, list]]


   .. py:method:: build_search_string(*nodes: str | SearchNode, joiner: SearchJoiner = 'AND') -> str

      Join one or more searches, and return a normalized search string.

      To negate, wrap in a negated search term:

          term = SearchNode(negated=col.group_searches(...))

      Invalid searches will throw an exception.



   .. py:method:: group_searches(*nodes: str | SearchNode, joiner: SearchJoiner = 'AND') -> SearchNode

      Join provided search nodes and strings into a single SearchNode.
      If a single SearchNode is provided, it is returned as-is.
      At least one node must be provided.



   .. py:method:: join_searches(existing_node: SearchNode, additional_node: SearchNode, operator: Literal['AND', 'OR']) -> str

      AND or OR `additional_term` to `existing_term`, without wrapping `existing_term` in brackets.
      Used by the Browse screen to avoid adding extra brackets when joining.
      If you're building a search query yourself, you probably don't need this.



   .. py:method:: replace_in_search_node(existing_node: SearchNode, replacement_node: SearchNode) -> str

      If nodes of the same type as `replacement_node` are found in existing_node, replace them.

      You can use this to replace any "deck" clauses in a search with a different deck for example.



   .. py:method:: all_browser_columns() -> collections.abc.Sequence[BrowserColumns]


   .. py:method:: get_browser_column(key: str) -> BrowserColumns | None


   .. py:method:: browser_row_for_id(id_: int) -> tuple[collections.abc.Generator[tuple[str, bool, BrowserRow], None, None], BrowserRow, str, int]


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

      Return the stored card column names and ensure the backend columns are set and in sync.



   .. py:method:: set_browser_card_columns(columns: list[str]) -> None


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

      Return the stored note column names and ensure the backend columns are set and in sync.



   .. py:method:: set_browser_note_columns(columns: list[str]) -> None


   .. py:method:: get_config(key: str, default: Any | None = None) -> Any


   .. py:method:: set_config(key: str, val: Any, *, undoable: bool = False) -> OpChanges

      Set a single config variable to any JSON-serializable value. The config
      is currently sent on every sync, so please don't store more than a few
      kilobytes in it.

      By default, no undo entry will be created, but the existing undo history
      will be preserved. Set `undoable=True` to allow the change to be undone;
      see undo code for how you can merge multiple undo entries.



   .. py:method:: remove_config(key: str) -> OpChanges


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

      This is a debugging aid. Prefer .get_config() when you know the key you need.



   .. py:method:: get_config_bool(key: anki.config.Config.Bool.V) -> bool


   .. py:method:: set_config_bool(key: anki.config.Config.Bool.V, value: bool, *, undoable: bool = False) -> OpChanges


   .. py:method:: get_config_string(key: anki.config.Config.String.V) -> str


   .. py:method:: set_config_string(key: anki.config.Config.String.V, value: str, undoable: bool = False) -> OpChanges


   .. py:method:: get_aux_notetype_config(id: anki.models.NotetypeId, key: str, default: Any | None = None) -> Any


   .. py:method:: set_aux_notetype_config(id: anki.models.NotetypeId, key: str, value: Any, *, undoable: bool = False) -> OpChanges


   .. py:method:: get_aux_template_config(id: anki.models.NotetypeId, card_ordinal: int, key: str, default: Any | None = None) -> Any


   .. py:method:: set_aux_template_config(id: anki.models.NotetypeId, card_ordinal: int, key: str, value: Any, *, undoable: bool = False) -> OpChanges


   .. py:attribute:: load_balancer_enabled


   .. py:attribute:: fsrs_short_term_with_steps_enabled


   .. py:method:: stats() -> anki.stats.CollectionStats


   .. py:method:: card_stats_data(card_id: anki.cards.CardId) -> anki.stats_pb2.CardStatsResponse

      Returns the data required to show card stats.

      If you wish to display the stats in a HTML table like Anki does,
      you can use the .js file directly - see this add-on for an example:
      https://ankiweb.net/shared/info/2179254157



   .. py:method:: get_review_logs(card_id: anki.cards.CardId) -> collections.abc.Sequence[anki.stats_pb2.CardStatsResponse.StatsRevlogEntry]


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


   .. py:method:: undo_status() -> UndoStatus

      Return the undo status.



   .. py:method:: add_custom_undo_entry(name: str) -> int

      Add an empty undo entry with the given name.
      The return value can be used to merge subsequent changes
      with `merge_undo_entries()`.

      You should only use this with your own custom actions - when
      extending default Anki behaviour, you should merge into an
      existing undo entry instead, so the existing undo name is
      preserved, and changes are processed correctly.



   .. py:method:: merge_undo_entries(target: int) -> OpChanges

      Combine multiple undoable operations into one.

      After a standard Anki action, you can use col.undo_status().last_step
      to retrieve the target to merge into. When defining your own custom
      actions, you can use `add_custom_undo_entry()` to define a custom
      undo name.



   .. py:method:: undo() -> OpChangesAfterUndo

      Returns result of backend undo operation, or throws UndoEmpty.



   .. py:method:: redo() -> OpChangesAfterUndo

      Returns result of backend redo operation, or throws UndoEmpty.



   .. py:method:: op_made_changes(changes: OpChanges) -> bool


   .. py:method:: fix_integrity() -> tuple[str, bool]

      Fix possible problems and rebuild caches.

      Returns tuple of (error: str, ok: bool). 'ok' will be true if no
      problems were found.



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


   .. py:method:: set_user_flag_for_cards(flag: int, cids: collections.abc.Sequence[anki.cards.CardId]) -> OpChangesWithCount


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


   .. py:method:: i18n_resources(modules: collections.abc.Sequence[str]) -> bytes


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


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


   .. py:method:: full_upload_or_download(*, auth: anki.sync.SyncAuth | None, server_usn: int | None, upload: bool) -> None


   .. py:method:: sync_login(username: str, password: str, endpoint: str | None) -> anki.sync.SyncAuth


   .. py:method:: sync_collection(auth: anki.sync.SyncAuth, sync_media: bool) -> anki.sync.SyncOutput


   .. py:method:: sync_media(auth: anki.sync.SyncAuth) -> None


   .. py:method:: sync_status(auth: anki.sync.SyncAuth) -> anki.sync.SyncStatus


   .. py:method:: media_sync_status() -> MediaSyncStatus

      This will throw if the sync failed with an error.



   .. py:method:: ankihub_login(id: str, password: str) -> str


   .. py:method:: ankihub_logout(token: str) -> None


   .. py:method:: get_preferences() -> Preferences


   .. py:method:: set_preferences(prefs: Preferences) -> OpChanges


   .. py:method:: render_markdown(text: str, sanitize: bool = True) -> str

      Not intended for public consumption at this time.



   .. py:method:: compare_answer(expected: str, provided: str, combining: bool = True) -> str


   .. py:method:: extract_cloze_for_typing(text: str, ordinal: int) -> str


   .. py:method:: compute_memory_state(card_id: anki.cards.CardId) -> ComputedMemoryState


   .. py:method:: fuzz_delta(card_id: anki.cards.CardId, interval: int) -> int

      The delta days of fuzz applied if reviewing the card in v3.



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


   .. py:method:: timeboxReached() -> Literal[False] | tuple[Any, int]

      Return (elapsedTime, reps) if timebox reached, or False.



   .. py:method:: log(*args: Any, **kwargs: Any) -> None


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

      Undo menu item name, or None if undo unavailable.



   .. py:method:: newNote(forDeck: bool = True) -> anki.notes.Note

      Return a new note with the current model.



   .. py:method:: addNote(note: anki.notes.Note) -> int


   .. py:method:: remNotes(ids: collections.abc.Sequence[anki.notes.NoteId]) -> None


   .. py:method:: card_stats(card_id: anki.cards.CardId, include_revlog: bool) -> str


   .. py:method:: cardStats(card: anki.cards.Card) -> str


   .. py:method:: updateFieldCache(nids: list[anki.notes.NoteId]) -> None


   .. py:method:: genCards(nids: list[anki.notes.NoteId]) -> list[int]


   .. py:method:: emptyCids() -> list[anki.cards.CardId]


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


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


.. py:function:: pb_export_limit(limit: ExportLimit) -> anki.import_export_pb2.ExportLimit

