Jump to content

Connect SuperML | Leeroopedia MCP: Equip your AI agents with best practices, code verification, and debugging knowledge. Powered by Leeroo — building Organizational Superintelligence. Contact us at founders@leeroo.com.

Principle:MarketSquare Robotframework browser Plugin Loading Mechanism

From Leeroopedia

Plugin Loading Mechanism

Overview

The robotframework-browser library supports dynamic plugin loading at library import time. When the Browser library is instantiated with a plugins argument, the specified plugin classes are discovered, instantiated, and their keywords are merged with the library's built-in keyword set. This entire process happens before any test execution begins, making plugin keywords available from the first test case.

Core Concept: Dynamic Discovery and Instantiation

Plugin loading follows a pipeline:

  1. Specification -- The user provides plugin identifiers (module paths, file paths, or comma-separated lists) via the plugins argument
  2. Parsing -- PluginParser from robotlibcore resolves each identifier to a Python class
  3. Instantiation -- Each plugin class is constructed with the Browser library instance as its argument
  4. Registration -- Plugin component instances are added to the library's component list
  5. Keyword Merging -- DynamicCore.__init__ collects keywords from all components (built-in and plugin)
  6. Tagging -- Plugin keywords are tracked in _plugin_keywords and auto-tagged with "Plugin"

Plugin Specification Format

Plugins are specified as a string (or list of strings) when importing the Browser library. Several formats are supported:

Module Path

*** Settings ***
Library    Browser    plugins=mypackage.myplugin.MyPlugin

The PluginParser imports the module and locates the class. The class must be a subclass of LibraryComponent.

File Path

*** Settings ***
Library    Browser    plugins=${CURDIR}/MyPlugin.py

When a file path is provided, PluginParser loads the module from the file system. The class name is inferred from the module contents.

Plugin with Arguments

*** Settings ***
Library    Browser    plugins=mypackage.MyPlugin;arg1;arg2

Semicolons separate the plugin path from positional arguments. These arguments are passed to the plugin constructor after the mandatory library parameter.

Multiple Plugins

*** Settings ***
Library    Browser    plugins=mypackage.PluginA,mypackage.PluginB

Comma-separated plugin specifications load multiple plugins simultaneously. Each is instantiated independently.

The Loading Pipeline in Detail

Step 1: Browser.__init__ Processes the plugins Argument

When the Browser class is instantiated, its __init__ method checks whether plugins is provided. The relevant code is at Browser/browser.py lines 894-900:

if plugins:
    parser = PluginParser(LibraryComponent, [self])
    parsed_plugins = parser.parse_plugins(plugins)
    libraries.extend(parsed_plugins)
    self._plugin_keywords = parser.get_plugin_keywords(parsed_plugins)
else:
    self._plugin_keywords = []

The libraries list already contains all built-in keyword modules (like Interaction, Getters, Network, etc.). Plugin instances are appended to this list.

Step 2: PluginParser Construction

PluginParser is instantiated with two arguments:

Argument Value Purpose
Base class LibraryComponent Specifies that all plugins must inherit from this class. PluginParser validates this.
Constructor args [self] (the Browser instance) Arguments passed to each plugin constructor. Since LibraryComponent.__init__ expects a Browser instance, the library passes itself.

Step 3: parse_plugins Resolves and Instantiates

parser.parse_plugins(plugins) handles the string parsing, module importing, class instantiation, and returns a list of plugin component instances. The PluginParser from robotlibcore:

  • Splits comma-separated plugin specifications
  • For each specification, splits on semicolons to separate the class path from arguments
  • Imports the module (by dotted path or file path)
  • Instantiates the class with [self] + extra_args
  • Validates that the instance is a subclass of LibraryComponent

Step 4: Keyword Collection

parser.get_plugin_keywords(parsed_plugins) extracts the keyword names from all plugin instances. These names are stored in self._plugin_keywords for later use in tagging.

Step 5: DynamicCore Registration

After plugins are appended to the libraries list, DynamicCore.__init__(self, libraries, translation_file) is called. This scans all components for @keyword-decorated methods and registers them as Robot Framework keywords.

Keyword Merging and Conflicts

Plugin keywords are merged into the same namespace as built-in keywords. This means:

  • No namespacing -- Plugin keywords are called by name just like built-in keywords
  • Name conflicts -- If a plugin defines a keyword with the same name as a built-in keyword, the behavior depends on the DynamicCore implementation (typically the last-registered wins)
  • Best practice -- Plugin authors should use unique, descriptive keyword names to avoid conflicts

Plugin Keyword Tagging

The Browser.get_keyword_tags() method (at lines 1301-1305) automatically adds the "Plugin" tag to any keyword whose name appears in self._plugin_keywords:

def get_keyword_tags(self, name: str) -> list:
    tags = list(DynamicCore.get_keyword_tags(self, name))
    if name in self._plugin_keywords:
        tags.append("Plugin")
    return tags

This provides a runtime mechanism to distinguish plugin keywords from built-in keywords without requiring plugin authors to manually tag their keywords.

Plugin Lifecycle

Phase Timing What Happens
Import Library Browser plugins=... Plugin classes are discovered, instantiated, and registered. JavaScript extensions are loaded.
Execution Test keywords are called Plugin keywords execute identically to built-in keywords.
Teardown Library scope ends No special plugin teardown mechanism. Plugins can implement Robot Framework listener methods if cleanup is needed.

Plugins can also implement the Robot Framework Listener API by setting ROBOT_LISTENER_API_VERSION on the class. The ExamplePlugin in the test suite demonstrates this with ROBOT_LISTENER_API_VERSION = 2 and an end_keyword method.

Error Handling

  • If a plugin module cannot be imported, PluginParser raises an ImportError during library instantiation
  • If a plugin class does not inherit from LibraryComponent, PluginParser raises a validation error
  • If a plugin's __init__ raises an exception (e.g., a JavaScript extension file not found), the error propagates and prevents library initialization

Domains

Implemented By

Related

Page Connections

Double-click a node to navigate. Hold to expand connections.
Principle
Implementation
Heuristic
Environment