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

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)
Supported by