How to list snapshot and remove by name using python API

The only action related to snapshot I found create_snapshot, switchto_snapshot, and remove_snapshot.

How I pass arguments to these method/functions?

These aren’t functions, there are actions with no data entry. You will have to use PyQt to access them in the snapshot docker, then modify the model.

Krita python developer tools may help in that regard.

Thanks, I will read the docs.

Some quick coding (only light testing done, better to test more corner cases before heavy use)

from datetime import datetime, timezone

from krita import Krita

from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QListView


def set_active_document(document):
    """ replacement for krita's borked Krita.setActiveDocument() """
    app = Krita.instance()
    active_window = app.activeWindow()

    # all windows ordered so that active is first
    windows = [active_window] + [w for w in app.windows() if w.qwindow() is not active_window.qwindow()]

    for window in windows:
        for view in window.views():
            if view.document() == document:
                window.showView(view)
                break


def find_snapshot_docker_and_item_view():
    app = Krita.instance()
    for docker in app.dockers():
        if docker.objectName() == 'Snapshot':
            item_view = docker.findChild(QListView)
            return docker, item_view
    return None, None  # not found ?


def create_document_snapshot(document=None, name=None):
    app = Krita.instance()
    if document is None:
        document = app.activeDocument()
    if document is None:
        raise RuntimeError('No document given / found.')
    if name is None:
        name = f'snapshot ({datetime.now(timezone.utc)})'

    # make sure that correct document is active.
    set_active_document(document)
    docker, item_view = find_snapshot_docker_and_item_view()
    model = item_view.model()

    # trigger action
    app.action('create_snapshot').trigger()

    # find last snapshot, and rename it
    last_row = model.rowCount() - 1
    rename_document_snapshot(document, last_row, name)
    switch_document_to_snapshot(document, last_row)
    return name, last_row


def rename_document_snapshot(document=None, old_name_or_row=None, new_name=None):
    app = Krita.instance()
    if document is None:
        document = app.activeDocument()
    if document is None:
        raise RuntimeError('No document given / found.')

    # make sure that correct document is active.
    set_active_document(document)
    docker, item_view = find_snapshot_docker_and_item_view()
    model = item_view.model()

    if not isinstance(new_name, str):
        raise TypeError(
                f'Invalid new_name, must be str (did get: '
                f'new_name = {new_name!r})')

    target_index = None
    if isinstance(old_name_or_row, int):
        target_index = model.index(int(old_name_or_row), 0)
    elif isinstance(old_name_or_row, str):
        for row in range(model.rowCount()):
            index = model.index(row, 0)
            if index.data(Qt.DisplayRole) == old_name_or_row:
                target_index = index
                break  # first matching found
    else:
        raise TypeError(
                f'Invalid old snapshot name / row, must be number or str (did get: '
                f'old_name_or_index = {old_name_or_row!r})')

    if not target_index or not target_index.isValid():
        raise ValueError(
                f'Failed to find old snapshot name / row, must be existing name or row (did get: '
                f'old_name_or_index = {old_name_or_row!r})')

    # change name of snapshot
    model.setData(target_index, new_name, role=Qt.EditRole)


def switch_document_to_snapshot(document=None, name_or_row=None):
    app = Krita.instance()
    if document is None:
        document = app.activeDocument()
    if document is None:
        raise RuntimeError('No document given / found.')

    # make sure that correct document is active.
    set_active_document(document)
    docker, item_view = find_snapshot_docker_and_item_view()
    model = item_view.model()

    target_index = None
    if isinstance(name_or_row, int):
        target_index = model.index(int(name_or_row), 0)
    elif isinstance(name_or_row, str):
        for row in range(model.rowCount()):
            index = model.index(row, 0)
            if index.data(Qt.DisplayRole) == name_or_row:
                target_index = index
                break  # first matching found
    else:
        raise TypeError(
                f'Invalid snapshot name / row, must be number or str (did get: '
                f'name_or_row = {name_or_row!r})')

    if not target_index or not target_index.isValid():
        raise ValueError(
                f'Failed to find snapshot name / row, must be existing name or row (did get: '
                f'name_or_row = {name_or_row!r})')

    # set current index and trigger snapshot switching
    item_view.setCurrentIndex(target_index)
    app.action('switchto_snapshot').trigger()


def remove_document_snapshot(document=None, name_or_row=None):
    app = Krita.instance()
    if document is None:
        document = app.activeDocument()
    if document is None:
        raise RuntimeError('No document given / found.')

    # make sure that correct document is active.
    set_active_document(document)
    docker, item_view = find_snapshot_docker_and_item_view()
    model = item_view.model()

    target_index = None
    if isinstance(name_or_row, int):
        target_index = model.index(int(name_or_row), 0)
    elif isinstance(name_or_row, str):
        for row in range(model.rowCount()):
            index = model.index(row, 0)
            if index.data(Qt.DisplayRole) == name_or_row:
                target_index = index
                break  # first matching found
    else:
        raise TypeError(
                f'Invalid snapshot name / row, must be number or str (did get: '
                f'name_or_row = {name_or_row!r})')

    if not target_index or not target_index.isValid():
        raise ValueError(
                f'Failed to find snapshot name / row, must be existing name or row (did get: '
                f'name_or_row = {name_or_row!r})')

    # set current index and trigger snapshot removing
    item_view.setCurrentIndex(target_index)
    app.action('remove_snapshot').trigger()


# testing
app = Krita.instance()
for i, document in enumerate(app.documents()):
    name, row = create_document_snapshot(document)
    # remove_document_snapshot(document, row)

Happy New Year 2026

/AkiR

Edit: removed unused QPersistentModelIndex import

1 Like

Thanks for your efforts and your time.

This topic was automatically closed 4 days after the last reply. New replies are no longer allowed.