OpenSesame
Rapunzel Code Editor
DataMatrix
Support forum
Python Tutorials
MindProbe
Supported by

SigmundAI.eu can now implement complete psychological experiments in #OpenSesame. From scratch based on verbal description. Astonishing how far #AI has come 😵‍💫 #psychology

[image or embed]

— Sebastiaan Mathôt (@cogsci.nl) Feb 23, 2026 at 3:56 PM

Creating an extension

What is an OpenSesame extension?

Extensions add arbitrary functionality to the OpenSesame user interface. For example, an extension can add a new entry to the main toolbar or the menubar. (To add functionality that you can use in experiments, you need a plugin.)

Relevant files

One or more extensions are put together in an extension package, which is always a subpackage of opensesame_extensions (which is itself a so-called implicit namespace package, but that's a technical detail that is not very important). Let's say that your extension package is called example, and that it contains a single extension (there can be more) called example_extension. This would correspond to the following file-and-folder structure:

opensesame_extensions/
    example/
        __init__.py               # can be empty but must exist
        example_extension/
            __init__.py           # contains extension information
            example_extension.py  # contains extension class

Extension information

Extension information is defined in the __init__.py of the extension module, so in our example this is opensesesame_extensions/example/example_extension/__init__.py.

"""A docstring with a description of the extension"""

# A standard icon name
# - <https://specifications.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html>
icon = 'applications-accessories'
# The label and the tooltip are used to create the default action, which is
# insert into the menu and/ or toolbar (or neither)
label = "Example extension"
tooltip = "Example tooltip"
menu = {
    "index": -1,
    "separator_before": True,
    "separator_after": True,
    "submenu": "Example"
}
toolbar = {
    "index": -1,
    "separator_before": True,
    "separator_after": True
}
# Settings are perstistently stored in the cfg object
settings = {
    "example_setting": "example value"
}

An extension can appear in the menu or main toolbar of OpenSesame. This requires that you define several fields in __init__.py as shown above:

  • The label is the text that will appear in the menu.
  • The icon is a freedesktop-compliant icon name that specifies the icon that will appear in the menu and/ or toolbar.
  • The index gives the position of the extension in the menu/ toolbar, and works like a list index. That is, negative values are relative to the last entry, where -1 puts your extension at the end.

To have your extension respond to menu/ toolbar activation, implement the activate() method as shown below in the extension code below.

Writing the extension code

The main extension code is placed in [extension_name].py. This file generally contains only a single class named [ExtensionName].py, that is, a class with the CamelCase equivalent of the plugin name, which inherits libqtopensesame.extensions.BaseExtension. So a basic (non-functional) extension class looks like this:

from libopensesame.py3compat import *
from libopensesame.oslogging import oslogger
from libqtopensesame.extensions import BaseExtension


class ExampleExtension(BaseExtension):
    """An example extension that lists several common events. The class name
    should be the CamelCase version of the folder_name and file_name. So in
    this case both the extension folder (which is a Python package) and the
    .py file (which is a Python module) are called example_extension, whereas
    the class is called ExampleExtension.
    """

    def activate(self):
        oslogger.debug('example_extension extension activated')

    def event_save_experiment(self, path):
        oslogger.debug(f'Event fired: save_experiment(path={path})')

    # See example_extension source code for more event listeners

Listening for events

OpenSesame fires events whenever something important happens. For example, the save_experiment event is fired when an experiment is saved. To have your extension listen to an event, simply implement a method with the name event_[event name] as shown above.

Note that some events take keyword arguments, such as path in the case of save_experiment. The keyword signature of your function must match the expected keyword signature. See the Event overview below for a full list of events and expected keywords.

Building a package and uploading to pypi

Building an extensin package and uploading it to pypi works the same way as it does for plugins:

Examples

For a working example, see:

Other examples can be found in the opensesame_extensions folder of the OpenSesame source code:

Event overview

This overview lists all events that are fired somewhere in the code, and that your extenstion can therefore listen to by implementing the corresponding event_[eventname]() functions.

change_experiment

Fired in: general_properties.py

extension_manager.fire(u'change_experiment')

change_item

Fired in: sequence.py

extension_manager.fire(u'change_item', name=self.name)

Fired in: qtitem.py

extension_manager.fire(u'change_item', name=self.name)

Fired in: loop.py

extension_manager.fire(u'change_item', name=self.name)

close

Fired in: qtopensesame.py

extension_manager.fire(u'close')

delete_item

Fired in: qtitem_store.py

extension_manager.fire(u'delete_item', name=name)

heartbeat

Fired in: multiprocess_runner.py

extension_manager.fire(u'heartbeat')

ide_jump_to_line

Fired in: SymbolSelector.py

extension_manager.fire('ide_jump_to_line', lineno=lineno)

Fired in: OpenSesameIDE.py

extension_manager.fire('ide_jump_to_line', lineno=line_number)

ide_new_file

Fired in: JupyterNotebook.py

extension_manager.fire(u'ide_new_file', source=code, ext=ext)

ide_save_current_file

Fired in: OpenSesameIDE.py

extension_manager.fire('ide_save_current_file')

image_annotations_detect

Fired in: JupyterNotebook.py

extension_manager.fire(u'image_annotations_detect', code=code)

jupyter_exception_occurred

Fired in: transparent_jupyter_widget.py

extension_manager.fire('jupyter_exception_occurred')

jupyter_execute_finished

Fired in: transparent_jupyter_widget.py

extension_manager.fire('jupyter_execute_finished')

jupyter_execute_result_text

Fired in: transparent_jupyter_widget.py

extension_manager.fire('jupyter_execute_result_text', text=text)

jupyter_execute_start

Fired in: transparent_jupyter_widget.py

extension_manager.fire('jupyter_execute_start')

jupyter_interrupt

Fired in: OpenSesameIDE.py

extension_manager.fire(u'jupyter_interrupt')

jupyter_restart

Fired in: console_bridge.py

extension_manager.fire(u'jupyter_restart')

Fired in: OpenSesameIDE.py

extension_manager.fire(u'jupyter_restart')

jupyter_run_code

Fired in: menubar.py

extension_manager.fire('jupyter_run_code',
                                                     code=command)

jupyter_run_system_command

Fired in: JupyterNotebook.py

extension_manager.fire('jupyter_run_system_command', cmd=cmd)

jupyter_show_prompt

Fired in: console_bridge.py

extension_manager.fire(u'jupyter_show_prompt')

jupyter_write

Fired in: console_bridge.py

extension_manager.fire(u'jupyter_write', msg=s)

new_item

Fired in: tree_overview.py

extension_manager.fire(u'new_item', name=item.name,
                _type=item.item_type)

new_linked_copy

Fired in: tree_overview.py

extension_manager.fire('new_linked_copy', name=item_name)

notify

Fired in: sequence.py

extension_manager.fire(u'notify',
                    message=_(u'Sequence contains non-existing item: %s')

Fired in: qtitem.py

extension_manager.fire(u'notify',
                        message=_(u'"%s" is set to a variable or '
                        u'unknown value and can only be edited through '
                        u'the script.')

Fired in: qtitem.py

extension_manager.fire(u'notify',
                        message=_(u'"%s" is defined using '
                        'variables and can only be edited through the '
                        'script.')

Fired in: qtitem.py

extension_manager.fire(u'notify',
                        message=_(u'"%s" is defined using '
                        u'variables or has an invalid value, and can only be '
                        u'edited through the script.')

Fired in: logger.py

extension_manager.fire(u'notify',
                    message=_(u'You have multiple unlinked loggers. This can lead to messy log files.')

Fired in: sketchpad_widget.py

extension_manager.fire(u'notify', message=notification,
                category=u'info')

open_experiment

Fired in: qtopensesame.py

extension_manager.fire(u'open_experiment', path=path)

open_item

Fired in: qtitem.py

extension_manager.fire(u'open_item', name=self.name)

pause_experiment

Fired in: base_runner.py

extension_manager.fire(u'pause_experiment')

prepare_change_experiment

Fired in: general_properties.py

extension_manager.fire(u'prepare_change_experiment')

prepare_delete_item

Fired in: qtitem_store.py

extension_manager.fire(u'prepare_delete_item', name=name)

prepare_open_item

Fired in: qtitem.py

extension_manager.fire(u'prepare_open_item', name=self.name)

prepare_purge_unused_items

Fired in: unused_widget.py

extension_manager.fire(u'prepare_purge_unused_items')

prepare_regenerate

Fired in: qtopensesame.py

extension_manager.fire(u'prepare_regenerate')

prepare_rename_item

Fired in: qtitem_store.py

extension_manager.fire(u'prepare_rename_item', from_name=from_name,
            to_name=to_name)

purge_unused_items

Fired in: unused_widget.py

extension_manager.fire(u'purge_unused_items')

pyqode_clear_breakpoints

Fired in: OpenSesameIDE.py

extension_manager.fire('pyqode_clear_breakpoints')

pyqode_resume_auto_backend_restart

Fired in: OpenSesameIDE.py

extension_manager.fire('pyqode_resume_auto_backend_restart')

Fired in: OpenSesameIDE.py

extension_manager.fire('pyqode_resume_auto_backend_restart')

Fired in: OpenSesameIDE.py

extension_manager.fire('pyqode_resume_auto_backend_restart')

Fired in: OpenSesameIDE.py

extension_manager.fire('pyqode_resume_auto_backend_restart')

pyqode_select_indentation_mode

Fired in: menubar.py

extension_manager.fire('pyqode_select_indentation_mode')

pyqode_suspend_auto_backend_restart

Fired in: OpenSesameIDE.py

extension_manager.fire('pyqode_suspend_auto_backend_restart')

Fired in: OpenSesameIDE.py

extension_manager.fire('pyqode_suspend_auto_backend_restart')

Fired in: OpenSesameIDE.py

extension_manager.fire('pyqode_suspend_auto_backend_restart')

Fired in: OpenSesameIDE.py

extension_manager.fire('pyqode_suspend_auto_backend_restart')

regenerate

Fired in: qtopensesame.py

extension_manager.fire(u'regenerate')

Fired in: qtopensesame.py

extension_manager.fire(u'regenerate')

register_editor

Fired in: qtplugin.py

extension_manager.fire(u'register_editor', editor=editor)

rename_item

Fired in: qtitem_store.py

extension_manager.fire(u'rename_item', from_name=from_name,
            to_name=to_name)

resume_experiment

Fired in: base_runner.py

extension_manager.fire(u'resume_experiment')

run_experiment_canceled

Fired in: base_runner.py

extension_manager.fire('run_experiment_canceled')

save_experiment

Fired in: qtopensesame.py

extension_manager.fire(u'save_experiment', path=self.current_path)

startup

Fired in: qtopensesame.py

extension_manager.fire(u'startup')

unregister_editor

Fired in: OpenSesameIDE.py

extension_manager.fire('unregister_editor', editor=editor)