CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-robotframework

Generic automation framework for acceptance testing and robotic process automation (RPA)

Pending
Overview
Eval results
Files

library-development.mddocs/

Library Development

Robot Framework provides comprehensive APIs for creating custom test libraries. Libraries can implement keywords using static, dynamic, or hybrid approaches, with full support for type conversion, argument handling, and test execution integration.

Capabilities

Library Decorators

Decorators for controlling keyword discovery and library behavior.

@keyword(name=None, tags=(), types=()):
    """
    Decorator to set custom name, tags, and argument types for keywords.
    
    Args:
        name: Custom keyword name (defaults to function name)
        tags: Sequence of tags to assign to the keyword
        types: Type hints for argument conversion
    """

@library(scope=None, version=None, converters=None, doc_format=None, 
         listener=None, auto_keywords=False):
    """
    Decorator to control library-wide settings and keyword discovery.
    
    Args:
        scope: Library scope ("GLOBAL", "SUITE", "TEST", "TASK")
        version: Library version
        converters: Custom type converters dictionary
        doc_format: Documentation format ("ROBOT", "HTML", "TEXT", "REST")
        listener: Listener instance for library events
        auto_keywords: Whether to automatically discover keywords
    """

@not_keyword:
    """
    Decorator to prevent functions from being exposed as keywords.
    """

Usage Examples:

from robot.api.deco import keyword, library, not_keyword

@library(scope='SUITE', version='1.0')
class MyLibrary:
    
    @keyword('Custom Keyword Name', tags=['web', 'ui'])
    def original_function_name(self, text, timeout=5):
        """Keyword with custom name and tags."""
        pass
    
    @keyword(types=[int, float])
    def calculate_sum(self, num1, num2):
        """Keyword with type conversion."""
        return num1 + num2
    
    @not_keyword
    def helper_method(self):
        """This method won't be exposed as a keyword."""
        pass
    
    def regular_keyword(self, arg1, arg2='default'):
        """Regular keyword discovered automatically."""
        pass

Exception Classes

Specialized exceptions for controlling test execution flow and reporting.

class Failure(AssertionError):
    """
    Report failed validation with HTML support.
    
    Args:
        message: Exception message
        html: When True, message is treated as HTML
    """
    def __init__(self, message: str, html: bool = False): ...

class ContinuableFailure(Failure):
    """
    Report failed validation but allow test execution to continue.
    """

class Error(RuntimeError):
    """
    Report error in execution (incorrect keyword usage).
    
    Args:
        message: Exception message  
        html: When True, message is treated as HTML
    """
    def __init__(self, message: str, html: bool = False): ...

class FatalError(Error):
    """
    Report error that stops the whole test execution.
    """

class SkipExecution(Exception):
    """
    Mark the executed test or task as skipped.
    
    Args:
        message: Skip reason message
        html: When True, message is treated as HTML
    """
    def __init__(self, message: str, html: bool = False): ...

Usage Examples:

from robot.api import Failure, ContinuableFailure, Error, SkipExecution

class ValidationLibrary:
    
    def validate_user_input(self, input_data):
        if not input_data:
            raise Failure("Input data cannot be empty")
        
        if len(input_data) < 3:
            raise ContinuableFailure(
                "Input too short, continuing with <em>warning</em>", 
                html=True
            )
    
    def connect_to_service(self, url):
        if not url.startswith(('http://', 'https://')):
            raise Error("Invalid URL format provided")
    
    def run_critical_test(self):
        try:
            self.perform_critical_operation()
        except CriticalSystemError:
            raise FatalError("Critical system failure - stopping all tests")
    
    def check_environment(self):
        if not self.is_test_environment_ready():
            raise SkipExecution("Test environment not ready, skipping test")

Logging API

Programmatic logging interface for test libraries.

def write(msg: str, level: str = "INFO", html: bool = False):
    """Write message to log file using specified level."""

def trace(msg: str, html: bool = False):
    """Write TRACE level message (not logged by default)."""

def debug(msg: str, html: bool = False):
    """Write DEBUG level message (not logged by default)."""

def info(msg: str, html: bool = False, also_console: bool = False):
    """Write INFO level message."""

def warn(msg: str, html: bool = False):
    """Write WARN level message (also shown in console)."""

def error(msg: str, html: bool = False):
    """Write ERROR level message (also shown in console)."""

def console(msg: str, newline: bool = True, stream: str = "stdout"):
    """Write message directly to console."""

Usage Examples:

from robot.api import logger

class DatabaseLibrary:
    
    def connect_to_database(self, connection_string):
        logger.info(f"Connecting to database: {connection_string}")
        
        try:
            self.connection = self._establish_connection(connection_string)
            logger.debug("Database connection established successfully")
        except Exception as e:
            logger.error(f"Failed to connect to database: {e}")
            raise
    
    def execute_query(self, query):
        logger.trace(f"Executing SQL query: {query}")
        
        if "DROP" in query.upper():
            logger.warn("Executing potentially destructive query", html=False)
        
        result = self.connection.execute(query)
        logger.info(f"Query returned {len(result)} rows")
        
        # Log HTML table of results
        html_table = self._format_as_html_table(result)
        logger.info(html_table, html=True)
        
        return result
    
    def backup_database(self):
        logger.console("Starting database backup...", stream="stdout")
        # Backup logic here
        logger.console("Database backup completed!", stream="stdout")

Library Interface Base Classes

Optional base classes for implementing different library APIs.

class DynamicLibrary:
    """
    Base class for libraries using the dynamic library API.
    Keywords are discovered and executed dynamically.
    """
    
    def get_keyword_names(self) -> Sequence[str]:
        """Return names of keywords this library implements (required)."""
    
    def run_keyword(self, name: str, args: tuple, named: dict):
        """Execute the specified keyword with given arguments (required)."""
    
    def get_keyword_documentation(self, name: str) -> str:
        """Return keyword documentation (optional)."""
    
    def get_keyword_arguments(self, name: str) -> Sequence:
        """Return keyword argument specification (optional)."""
    
    def get_keyword_types(self, name: str):
        """Return keyword argument types (optional)."""
    
    def get_keyword_tags(self, name: str) -> Sequence[str]:
        """Return keyword tags (optional)."""
    
    def get_keyword_source(self, name: str) -> str:
        """Return keyword source information (optional)."""

class HybridLibrary:
    """
    Base class for libraries using the hybrid library API.
    Combines static and dynamic approaches.
    """
    
    def get_keyword_names(self) -> Sequence[str]:
        """Return names of keywords this library implements (required)."""

Usage Examples:

from robot.api.interfaces import DynamicLibrary

class RestApiLibrary(DynamicLibrary):
    
    def __init__(self, base_url=""):
        self.base_url = base_url
        self.session = self._create_session()
    
    def get_keyword_names(self):
        return ['GET Request', 'POST Request', 'PUT Request', 'DELETE Request',
                'Set Base URL', 'Set Headers', 'Verify Status Code']
    
    def run_keyword(self, name, args, named):
        method_name = name.lower().replace(' ', '_')
        method = getattr(self, method_name)
        return method(*args, **named)
    
    def get_keyword_documentation(self, name):
        docs = {
            'GET Request': 'Send HTTP GET request to specified endpoint',
            'POST Request': 'Send HTTP POST request with data',
            'Verify Status Code': 'Verify the HTTP response status code'
        }
        return docs.get(name, '')
    
    def get_keyword_arguments(self, name):
        args = {
            'GET Request': ['endpoint', 'params={}', 'headers={}'],
            'POST Request': ['endpoint', 'data', 'headers={}'],
            'Verify Status Code': ['expected_code']
        }
        return args.get(name, [])
    
    def get_keyword_tags(self, name):
        if 'Request' in name:
            return ['http', 'api']
        return ['verification']
    
    # Keyword implementations
    def get_request(self, endpoint, params=None, headers=None):
        url = f"{self.base_url}{endpoint}"
        response = self.session.get(url, params=params, headers=headers)
        self.last_response = response
        return response
    
    def verify_status_code(self, expected_code):
        actual_code = self.last_response.status_code
        if actual_code != int(expected_code):
            raise Failure(f"Expected status {expected_code}, got {actual_code}")

Listener Interfaces

Monitor and react to test execution events.

class ListenerV2:
    """
    Base class for listener API version 2.
    Provides hooks for test execution events.
    """
    
    def start_suite(self, name, attributes): ...
    def end_suite(self, name, attributes): ...
    def start_test(self, name, attributes): ...
    def end_test(self, name, attributes): ...
    def start_keyword(self, name, attributes): ...
    def end_keyword(self, name, attributes): ...
    def log_message(self, message): ...
    def message(self, message): ...
    def library_import(self, name, attributes): ...
    def resource_import(self, name, attributes): ...
    def variables_import(self, name, attributes): ...
    def output_file(self, path): ...
    def close(self): ...

class ListenerV3:
    """
    Base class for listener API version 3.
    Enhanced version with additional event information.
    """
    
    # Similar methods to ListenerV2 but with enhanced attributes
    def start_suite(self, data, result): ...
    def end_suite(self, data, result): ...
    def start_test(self, data, result): ...
    def end_test(self, data, result): ...
    # Additional methods for control structures
    def start_if(self, data, result): ...
    def end_if(self, data, result): ...
    def start_for(self, data, result): ...
    def end_for(self, data, result): ...

Usage Examples:

from robot.api.interfaces import ListenerV2
import time

class TestTimingListener(ListenerV2):
    
    def __init__(self):
        self.suite_times = {}
        self.test_times = {}
    
    def start_suite(self, name, attributes):
        self.suite_times[name] = {'start': time.time()}
        print(f"Suite '{name}' started")
    
    def end_suite(self, name, attributes):
        start_time = self.suite_times[name]['start']
        duration = time.time() - start_time
        print(f"Suite '{name}' completed in {duration:.2f} seconds")
    
    def start_test(self, name, attributes):
        self.test_times[name] = {'start': time.time()}
    
    def end_test(self, name, attributes):
        start_time = self.test_times[name]['start']  
        duration = time.time() - start_time
        status = attributes['status']
        print(f"Test '{name}' {status} in {duration:.2f} seconds")
    
    def log_message(self, message):
        level = message['level']
        if level == 'ERROR':
            print(f"ERROR LOGGED: {message['message']}")

Custom Parser Interface

Create custom parsers for non-standard test data formats.

class Parser:
    """
    Base class for custom parsers.
    """
    
    extension: Union[str, Sequence[str]]  # File extensions this parser handles
    
    def parse(self, source: Path, defaults) -> TestSuite:
        """Parse source file into TestSuite (required)."""
    
    def parse_init(self, source: Path, defaults) -> TestSuite:
        """Parse suite initialization file (optional)."""

Usage Examples:

from robot.api.interfaces import Parser
from robot.api import TestSuite
import json
from pathlib import Path

class JsonTestParser(Parser):
    extension = '.json'
    
    def parse(self, source: Path, defaults):
        with open(source) as f:
            data = json.load(f)
        
        suite = TestSuite(
            name=data.get('name', source.stem),
            doc=data.get('documentation', ''),
            source=str(source)
        )
        
        # Parse test cases from JSON
        for test_data in data.get('tests', []):
            test = suite.tests.create(
                name=test_data['name'],
                doc=test_data.get('doc', '')
            )
            
            # Add keywords from JSON structure
            for keyword_data in test_data.get('keywords', []):
                test.keywords.create(
                    name=keyword_data['name'],
                    args=keyword_data.get('args', [])
                )
        
        return suite

Types

# Library scope options
Scope = Literal["GLOBAL", "SUITE", "TEST", "TASK"]

# Documentation format options
DocFormat = Literal["ROBOT", "HTML", "TEXT", "REST"]

# Logging levels
LOGLEVEL = Literal["TRACE", "DEBUG", "INFO", "CONSOLE", "HTML", "WARN", "ERROR"]

# Library interface types
Name = str
Arguments = Sequence[Union[str, Tuple[str], Tuple[str, Any]]]
Documentation = str
Tags = Sequence[str]
Source = str

# Parser interface types
TestDefaults = object  # Default values and settings for test execution

# Type hint specifications
TypeHint = Union[type, str, Tuple["TypeHint", ...]]
TypeHints = Union[Mapping[str, TypeHint], Sequence[TypeHint]]

# Converter function signature
Converter = Union[Callable[[Any], Any], Callable[[Any, Any], Any]]

Install with Tessl CLI

npx tessl i tessl/pypi-robotframework

docs

builtin-libraries.md

configuration-variables.md

core-execution.md

index.md

library-development.md

parsing-model.md

tile.json