Eine Erweiterung erstellen
- Was ist eine OpenSesame-Erweiterung?
- Relevante Dateien
- Erweiterungsinformationen
- Schreiben des Erweiterungscodes
- Lauschen auf Ereignisse
- Ein Paket erstellen und auf pypi hochladen
- Beispiele
- Ereignisübersicht
- change_experiment
- change_item
- close
- delete_item
- heartbeat
- ide_jump_to_line
- ide_new_file
- ide_save_current_file
- image_annotations_detect
- jupyter_exception_occurred
- jupyter_execute_finished
- jupyter_execute_result_text
- jupyter_execute_start
- jupyter_interrupt
- jupyter_restart
- jupyter_run_code
- jupyter_run_system_command
- jupyter_show_prompt
- jupyter_write
- new_item
- new_linked_copy
- notify
- open_experiment
- open_item
- pause_experiment
- prepare_change_experiment
- prepare_delete_item
- prepare_open_item
- prepare_purge_unused_items
- prepare_regenerate
- prepare_rename_item
- purge_unused_items
- pyqode_clear_breakpoints
- pyqode_resume_auto_backend_restart
- pyqode_select_indentation_mode
- pyqode_suspend_auto_backend_restart
- regenerate
- register_editor
- rename_item
- resume_experiment
- run_experiment_canceled
- save_experiment
- startup
- unregister_editor
Was ist eine OpenSesame-Erweiterung?
Erweiterungen fügen der OpenSesame-Benutzeroberfläche beliebige Funktionen hinzu. Zum Beispiel kann eine Erweiterung einen neuen Eintrag in der Hauptwerkzeugleiste oder der Menüleiste hinzufügen. (Um Funktionen hinzuzufügen, die Sie in Experimenten verwenden können, benötigen Sie ein Plugin.)
Relevante Dateien
Eine oder mehrere Erweiterungen werden in einem Erweiterungspaket zusammengefasst, das immer ein Unterpaket von opensesame_extensions
ist (das selbst ein sogenanntes implizites Namespace-Paket ist, aber das ist ein technisches Detail, das nicht sehr wichtig ist). Nehmen wir an, Ihr Erweiterungspaket heißt example
, und es enthält eine einzelne Erweiterung (es können mehr sein) namens example_extension
. Dies würde der folgenden Datei- und Verzeichnisstruktur entsprechen:
opensesame_extensions/
example/
__init__.py # kann leer sein, muss aber vorhanden sein
example_extension/
__init__.py # enthält Erweiterungsinformationen
example_extension.py # enthält Erweiterungsklasse
Erweiterungsinformationen
Erweiterungsinformationen sind in der __init__.py
des Erweiterungsmoduls definiert, also in unserem Beispiel ist das opensesesame_extensions/example/example_extension/__init__.py
.
"""Ein Docstring mit einer Beschreibung der Erweiterung"""
# Ein Standard-Icon-Name
# - <https://specifications.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html>
icon = 'applications-accessories'
# Das Label und der Tooltip werden verwendet, um die Standardaktion zu erstellen, die
# im Menü und/oder der Werkzeugleiste (oder keiner von beiden) eingefügt wird
label = "Beispiel-Erweiterung"
tooltip = "Beispiel-Tooltip"
menu = {
"index": -1,
"separator_before": True,
"separator_after": True,
"submenu": "Beispiel"
}
toolbar = {
"index": -1,
"separator_before": True,
"separator_after": True
}
# Einstellungen werden dauerhaft im cfg-Objekt gespeichert
settings = {
"example_setting": "example value"
}
Eine Erweiterung kann im Menü oder in der Hauptwerkzeugleiste von OpenSesame erscheinen. Dazu müssen Sie mehrere Felder in __init__.py
definieren, wie oben gezeigt:
- Das
label
ist der Text, der im Menü erscheinen wird. - Das
icon
ist ein freedesktop-konformer Icon-Name, der das Icon angibt, das im Menü und/oder in der Werkzeugleiste erscheinen wird. - Der
index
gibt die Position der Erweiterung im Menü/der Werkzeugleiste an und funktioniert wie einlist
-Index. Das heißt, negative Werte beziehen sich auf den letzten Eintrag, wobei -1 Ihre Erweiterung am Ende platziert.
Um Ihre Erweiterung auf Menü-/Werkzeugleistenaktivierung zu reagieren, implementieren Sie die activate()
-Methode, wie unten in dem Erweiterungscode gezeigt.
Schreiben des Erweiterungscodes
Der Haupterweiterungscode befindet sich in [extension_name].py
. Diese Datei enthält in der Regel nur eine einzige Klasse mit dem Namen [ExtensionName].py
, also eine Klasse mit dem CamelCase-Äquivalent des Plugin-Namens, die von libqtopensesame.extensions.BaseExtension
erbt. Eine grundlegende (nicht funktionale) Erweiterungsklasse sieht also so aus:
from libopensesame.py3compat import *
from libopensesame.oslogging import oslogger
from libqtopensesame.extensions import BaseExtension
class ExampleExtension(BaseExtension):
"""Eine Beispiel-Erweiterung, die mehrere häufige Ereignisse auflistet. Der Klassenname
sollte die CamelCase-Version des folder_name und file_name sein. Also in
diesem Fall sind sowohl der Erweiterungsordner (der ein Python-Paket ist) als auch die
.py-Datei (die ein Python-Modul ist) mit example_extension benannt, während
die Klasse ExampleExtension genannt ist.
"""
def activate(self):
oslogger.debug('example_extension Erweiterung aktiviert')
def event_save_experiment(self, path):
oslogger.debug(f'Ereignis ausgelöst: save_experiment(path={path})')
# Weitere Ereignislistener finden Sie im Beispiel-Code von example_extension
Lauschen auf Ereignisse
OpenSesame löst Ereignisse aus, wenn etwas Wichtiges passiert. Zum Beispiel wird das Ereignis save_experiment
ausgelöst, wenn ein Experiment gespeichert wird. Um Ihre Erweiterung auf ein Ereignis hören zu lassen, implementieren Sie einfach eine Methode mit dem Namen event_[event name]
, wie oben gezeigt.
Beachten Sie, dass einige Ereignisse Schlüsselwortargumente verwenden, wie path
im Falle von save_experiment
. Die Schlüsselwortsygnatur Ihrer Funktion muss der erwarteten Schlüsselwortsygnatur entsprechen. Siehe die Ereignisübersicht unten für eine vollständige Liste der Ereignisse und erwarteten Schlüsselwörter.
Ein Paket erstellen und auf pypi hochladen
Ein Extension-Paket erstellen und auf pypi
hochladen funktioniert genauso wie für Plugins:
- https://osdoc.cogsci.nl/4.0/de/dev/plugin
- https://github.com/open-cogsci/opensesame-extension-example
Beispiele
Für ein funktionierendes Beispiel siehe:
Weitere Beispiele finden Sie im Ordner opensesame_extensions
des OpenSesame-Quellcodes:
Ereignisübersicht
In dieser Übersicht sind alle Ereignisse aufgeführt, die irgendwo im Code ausgelöst werden und auf die Ihre Erweiterung daher hören kann, indem sie die entsprechenden event_[eventname]()
Funktionen implementiert.
change_experiment
Ausgelöst in: general_properties.py
extension_manager.fire(u'change_experiment')
change_item
Ausgelöst in: sequence.py
extension_manager.fire(u'change_item', name=self.name)
Ausgelöst in: qtitem.py
extension_manager.fire(u'change_item', name=self.name)
Ausgelöst in: loop.py
extension_manager.fire(u'change_item', name=self.name)
close
Ausgelöst in: qtopensesame.py
extension_manager.fire(u'close')
delete_item
Ausgelöst in: qtitem_store.py
extension_manager.fire(u'delete_item', name=name)
heartbeat
Ausgelöst in: multiprocess_runner.py
extension_manager.fire(u'heartbeat')
ide_jump_to_line
Ausgelöst in: SymbolSelector.py
extension_manager.fire('ide_jump_to_line', lineno=lineno)
Ausgelöst in: OpenSesameIDE.py
extension_manager.fire('ide_jump_to_line', lineno=line_number)
ide_new_file
Ausgelöst in: JupyterNotebook.py
extension_manager.fire(u'ide_new_file', source=code, ext=ext)
ide_save_current_file
Ausgelöst in: OpenSesameIDE.py
extension_manager.fire('ide_save_current_file')
image_annotations_detect
Ausgelöst in: JupyterNotebook.py
extension_manager.fire(u'image_annotations_detect', code=code)
jupyter_exception_occurred
Ausgelöst in: transparent_jupyter_widget.py
extension_manager.fire('jupyter_exception_occurred')
jupyter_execute_finished
Ausgelöst in: transparent_jupyter_widget.py
extension_manager.fire('jupyter_execute_finished')
jupyter_execute_result_text
Ausgelöst in: transparent_jupyter_widget.py
extension_manager.fire('jupyter_execute_result_text', text=text)
jupyter_execute_start
Ausgelöst in: transparent_jupyter_widget.py
extension_manager.fire('jupyter_execute_start')
jupyter_interrupt
Ausgelöst in: OpenSesameIDE.py
extension_manager.fire(u'jupyter_interrupt')
jupyter_restart
Ausgelöst in: console_bridge.py
extension_manager.fire(u'jupyter_restart')
Ausgelöst in: OpenSesameIDE.py
extension_manager.fire(u'jupyter_restart')
jupyter_run_code
Ausgelöst in: menubar.py
extension_manager.fire('jupyter_run_code',
code=command)
jupyter_run_system_command
Ausgelöst in: JupyterNotebook.py
extension_manager.fire('jupyter_run_system_command', cmd=cmd)
jupyter_show_prompt
Ausgelöst in: console_bridge.py
extension_manager.fire(u'jupyter_show_prompt')
jupyter_write
Ausgelöst in: console_bridge.py
extension_manager.fire(u'jupyter_write', msg=s)
new_item
Ausgelöst in: tree_overview.py
extension_manager.fire(u'new_item', name=item.name,
_type=item.item_type)
new_linked_copy
Ausgelöst in: tree_overview.py
extension_manager.fire('new_linked_copy', name=item_name)
notify
Ausgelöst in: sequence.py
extension_manager.fire(u'notify',
message=_(u'Sequence contains non-existing item: %s')
Ausgelöst 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.')
Ausgelöst in: qtitem.py
extension_manager.fire(u'notify',
message=_(u'"%s" is defined using '
'variables and can only be edited through the '
'script.')
Ausgelöst 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.')
Ausgelöst in: logger.py
extension_manager.fire(u'notify',
message=_(u'You have multiple unlinked loggers. This can lead to messy log files.')
Ausgelöst in: sketchpad_widget.py
extension_manager.fire(u'notify', message=notification,
category=u'info')
open_experiment
Ausgelöst in: qtopensesame.py
extension_manager.fire(u'open_experiment', path=path)
open_item
Ausgelöst in: qtitem.py
extension_manager.fire(u'open_item', name=self.name)
pause_experiment
Ausgelöst in: base_runner.py
extension_manager.fire(u'pause_experiment')
prepare_change_experiment
Ausgelöst in: general_properties.py
extension_manager.fire(u'prepare_change_experiment')
prepare_delete_item
Ausgelöst in: qtitem_store.py
extension_manager.fire(u'prepare_delete_item', name=name)
prepare_open_item
Ausgelöst in: qtitem.py
extension_manager.fire(u'prepare_open_item', name=self.name)
prepare_purge_unused_items
Ausgelöst in: unused_widget.py
extension_manager.fire(u'prepare_purge_unused_items')
prepare_regenerate
Ausgelöst in: qtopensesame.py
extension_manager.fire(u'prepare_regenerate')
prepare_rename_item
Ausgelöst in: qtitem_store.py
extension_manager.fire(u'prepare_rename_item', from_name=from_name,
to_name=to_name)
purge_unused_items
Ausgelöst in: unused_widget.py
extension_manager.fire(u'purge_unused_items')
pyqode_clear_breakpoints
Ausgelöst in: OpenSesameIDE.py
extension_manager.fire('pyqode_clear_breakpoints')
pyqode_resume_auto_backend_restart
Ausgelöst in: OpenSesameIDE.py
extension_manager.fire('pyqode_resume_auto_backend_restart')
Ausgelöst in: OpenSesameIDE.py
extension_manager.fire('pyqode_resume_auto_backend_restart')
Ausgelöst in: OpenSesameIDE.py
extension_manager.fire('pyqode_resume_auto_backend_restart')
Ausgelöst in: OpenSesameIDE.py
extension_manager.fire('pyqode_resume_auto_backend_restart')
pyqode_select_indentation_mode
Ausgelöst in: menubar.py
extension_manager.fire('pyqode_select_indentation_mode')
pyqode_suspend_auto_backend_restart
Ausgelöst in: OpenSesameIDE.py
extension_manager.fire('pyqode_suspend_auto_backend_restart')
Ausgelöst in: OpenSesameIDE.py
extension_manager.fire('pyqode_suspend_auto_backend_restart')
Ausgelöst in: OpenSesameIDE.py
extension_manager.fire('pyqode_suspend_auto_backend_restart')
Ausgelöst in: OpenSesameIDE.py
extension_manager.fire('pyqode_suspend_auto_backend_restart')
regenerate
Ausgelöst in: qtopensesame.py
extension_manager.fire(u'regenerate')
Ausgeführt in: qtopensesame.py
extension_manager.fire(u'neu_generieren')
register_editor
Ausgeführt in: qtplugin.py
extension_manager.fire(u'register_editor', editor=editor)
rename_item
Ausgeführt in: qtitem_store.py
extension_manager.fire(u'benenne_item_um', from_name=from_name,
to_name=to_name)
resume_experiment
Ausgeführt in: base_runner.py
extension_manager.fire(u'fortsetzen_experiment')
run_experiment_canceled
Ausgeführt in: base_runner.py
extension_manager.fire('lauf_experiment_abgebrochen')
save_experiment
Ausgeführt in: qtopensesame.py
extension_manager.fire(u'speichern_experiment', path=self.current_path)
startup
Ausgeführt in: qtopensesame.py
extension_manager.fire(u'startup')
unregister_editor
Ausgeführt in: OpenSesameIDE.py
extension_manager.fire('editor_abmelden', editor=editor)