Extend listener with pre-import events
Context
Born from this discussion on Slack: https://robotframework.slack.com/archives/C015KB1QSDN/p1775116818448659
Robot includes the Listener API:
Robot Framework's listener interface provides a powerful mechanism for getting notifications and for inspecting and modifying data and results during execution.
Recently, I tried to use this API to centrally change library arguments for every library import. In doing so, I found out that the listener API only provides events after the importing is already done. For my use case, I must have an event before the import starts. This applies to both listener v2 and v3.
Goal
Extend the listener API with the following events:
- Before Library import starts
- Before Resource import starts
- Before Variables import starts
Possible design
The current listeners already support the events library_import, resource_import, and variables_import. These events don't need to change.
Add the following events to listener v3:
start_library_importstart_resource_importstart_variables_import
Adding these events may look somethings like this:
Option 1: Reusing importer
class Example:
ROBOT_LISTENER_API_VERSION = 3
def start_library_import(self, importer: robot.running.resourcemodel.Import):
# Does not currently exist
def library_import(self, library: robot.running.testlibraries.TestLibrary, importer: robot.running.resourcemodel.Import):
# Already exists, is unchanged
def start_resource_import(self, importer: robot.running.resourcemodel.Import):
# Does not currently exist
def resource_import(self, resource: robot.running.resourcemodel.ResourceFile, importer: robot.running.resourcemodel.Import):
# Already exists, is unchanged
def start_variables_import(self, importer: robot.running.resourcemodel.Import):
# Does not currently exist
def variables_import(self, attrs, importer: robot.running.resourcemodel.Import):
# Already exists, is unchangedOption 2: Reusing parser nodes
class Example:
ROBOT_LISTENER_API_VERSION = 3
def start_library_import(self, node: robot.parsing.model.statements.LibraryImport):
# Does not currently exist
def library_import(self, library: robot.running.testlibraries.TestLibrary, importer: robot.running.resourcemodel.Import):
# Already exists, is unchanged
def start_resource_import(self, node: robot.parsing.model.statements.ResourceImport):
# Does not currently exist
def resource_import(self, resource: robot.running.resourcemodel.ResourceFile, importer: robot.running.resourcemodel.Import):
# Already exists, is unchanged
def start_variables_import(self, node: robot.parsing.model.statements.VariablesImport):
# Does not currently exist
def variables_import(self, attrs, importer: robot.running.resourcemodel.Import):
# Already exists, is unchangedOptional additions
Make an alias for the following, already existing, functions:
library_import -> start_library_import
resource_import -> start_resource_import
variables_import -> start_variables_import
This could be implemented in backwards compatible manner so that we'd add new start/end_library/resource/variables_import hooks. Old library/resource/variables_import hooks could be preserved and called if the matching end_xxx_import methods weren't defined. Thus there would be no need changes to the listener API version. ~Pekka
Acceptance criteria
- The new
start_*_importevents are called before the relevant file is imported. - The new
start_*_importevents receive data on what will be imported. - The listener can control imports using the new
start_*_importevents- The listener can change the file that will be imported
- The listener can change the arguments with which the file is imported
- The listener can change the alias with which the library is imported (only applies to library imports)
Source: robotframework/robotframework