Skip to content

robot.model.body

BodyItem

Bases: ModelObject

from_dict classmethod

from_dict(data: DataDict) -> T

Create this object based on data in a dictionary.

Data can be got from the :meth:to_dict method or created externally.

With robot.running model objects new in Robot Framework 6.1, with robot.result new in Robot Framework 7.0.

Source code in src/robot/model/modelobject.py
@classmethod
def from_dict(cls: Type[T], data: DataDict) -> T:
    """Create this object based on data in a dictionary.

    Data can be got from the :meth:`to_dict` method or created externally.

    With ``robot.running`` model objects new in Robot Framework 6.1,
    with ``robot.result`` new in Robot Framework 7.0.
    """
    try:
        return cls().config(**data)
    except (AttributeError, TypeError) as err:
        raise DataError(f"Creating '{full_name(cls)}' object from dictionary "
                        f"failed: {err}")

from_json classmethod

from_json(source: str | bytes | TextIO | Path) -> T

Create this object based on JSON data.

The data is given as the source parameter. It can be:

  • a string (or bytes) containing the data directly,
  • an open file object where to read the data from, or
  • a path (pathlib.Path or string) to a UTF-8 encoded file to read.

The JSON data is first converted to a Python dictionary and the object created using the :meth:from_dict method.

Notice that the source is considered to be JSON data if it is a string and contains {. If you need to use { in a file system path, pass it in as a pathlib.Path instance.

With robot.running model objects new in Robot Framework 6.1, with robot.result new in Robot Framework 7.0.

Source code in src/robot/model/modelobject.py
@classmethod
def from_json(cls: Type[T], source: 'str|bytes|TextIO|Path') -> T:
    """Create this object based on JSON data.

    The data is given as the ``source`` parameter. It can be:

    - a string (or bytes) containing the data directly,
    - an open file object where to read the data from, or
    - a path (``pathlib.Path`` or string) to a UTF-8 encoded file to read.

    The JSON data is first converted to a Python dictionary and the object
    created using the :meth:`from_dict` method.

    Notice that the ``source`` is considered to be JSON data if it is
    a string and contains ``{``. If you need to use ``{`` in a file system
    path, pass it in as a ``pathlib.Path`` instance.

    With ``robot.running`` model objects new in Robot Framework 6.1,
    with ``robot.result`` new in Robot Framework 7.0.
    """
    try:
        data = JsonLoader().load(source)
    except (TypeError, ValueError) as err:
        raise DataError(f'Loading JSON data failed: {err}')
    return cls.from_dict(data)

to_json

1
2
3
4
5
6
7
to_json(
    file: None = None,
    *,
    ensure_ascii: bool = False,
    indent: int = 0,
    separators: tuple[str, str] = (",", ":")
) -> str
1
2
3
4
5
6
7
to_json(
    file: TextIO | Path | str,
    *,
    ensure_ascii: bool = False,
    indent: int = 0,
    separators: tuple[str, str] = (",", ":")
) -> None
1
2
3
4
5
6
7
to_json(
    file: None | TextIO | Path | str = None,
    *,
    ensure_ascii: bool = False,
    indent: int = 0,
    separators: tuple[str, str] = (",", ":")
) -> str | None

Serialize this object into JSON.

The object is first converted to a Python dictionary using the :meth:to_dict method and then the dictionary is converted to JSON.

The file parameter controls what to do with the resulting JSON data. It can be:

  • None (default) to return the data as a string,
  • an open file object where to write the data to, or
  • a path (pathlib.Path or string) to a file where to write the data using UTF-8 encoding.

JSON formatting can be configured using optional parameters that are passed directly to the underlying json__ module. Notice that the defaults differ from what json uses.

With robot.running model objects new in Robot Framework 6.1, with robot.result new in Robot Framework 7.0.

__ https://docs.python.org/3/library/json.html

Source code in src/robot/model/modelobject.py
def to_json(self, file: 'None|TextIO|Path|str' = None, *,
            ensure_ascii: bool = False, indent: int = 0,
            separators: 'tuple[str, str]' = (',', ':')) -> 'str|None':
    """Serialize this object into JSON.

    The object is first converted to a Python dictionary using the
    :meth:`to_dict` method and then the dictionary is converted to JSON.

    The ``file`` parameter controls what to do with the resulting JSON data.
    It can be:

    - ``None`` (default) to return the data as a string,
    - an open file object where to write the data to, or
    - a path (``pathlib.Path`` or string) to a file where to write
      the data using UTF-8 encoding.

    JSON formatting can be configured using optional parameters that
    are passed directly to the underlying json__ module. Notice that
    the defaults differ from what ``json`` uses.

    With ``robot.running`` model objects new in Robot Framework 6.1,
    with ``robot.result`` new in Robot Framework 7.0.

    __ https://docs.python.org/3/library/json.html
    """
    return JsonDumper(ensure_ascii=ensure_ascii, indent=indent,
                      separators=separators).dump(self.to_dict(), file)

config

config(**attributes) -> T

Configure model object with given attributes.

obj.config(name='Example', doc='Something') is equivalent to setting obj.name = 'Example' and obj.doc = 'Something'.

New in Robot Framework 4.0.

Source code in src/robot/model/modelobject.py
def config(self: T, **attributes) -> T:
    """Configure model object with given attributes.

    ``obj.config(name='Example', doc='Something')`` is equivalent to setting
    ``obj.name = 'Example'`` and ``obj.doc = 'Something'``.

    New in Robot Framework 4.0.
    """
    for name, value in attributes.items():
        try:
            orig = getattr(self, name)
        except AttributeError:
            raise AttributeError(f"'{full_name(self)}' object does not have "
                                 f"attribute '{name}'")
        # Preserve tuples. Main motivation is converting lists with `from_json`.
        if isinstance(orig, tuple) and not isinstance(value, tuple):
            try:
                value = tuple(value)
            except TypeError:
                raise TypeError(f"'{full_name(self)}' object attribute '{name}' "
                                f"is 'tuple', got '{type_name(value)}'.")
        try:
            setattr(self, name, value)
        except AttributeError as err:
            # Ignore error setting attribute if the object already has it.
            # Avoids problems with `from_dict` with body items having
            # un-settable `type` attribute that is needed in dict data.
            if value != orig:
                raise AttributeError(f"Setting attribute '{name}' failed: {err}")
    return self

copy

copy(**attributes) -> T

Return a shallow copy of this object.

:param attributes: Attributes to be set to the returned copy. For example, obj.copy(name='New name').

See also :meth:deepcopy. The difference between copy and deepcopy is the same as with the methods having same names in the copy__ module.

__ https://docs.python.org/3/library/copy.html

Source code in src/robot/model/modelobject.py
def copy(self: T, **attributes) -> T:
    """Return a shallow copy of this object.

    :param attributes: Attributes to be set to the returned copy.
        For example, ``obj.copy(name='New name')``.

    See also :meth:`deepcopy`. The difference between ``copy`` and
    ``deepcopy`` is the same as with the methods having same names in
    the copy__ module.

    __ https://docs.python.org/3/library/copy.html
    """
    return copy.copy(self).config(**attributes)

deepcopy

deepcopy(**attributes) -> T

Return a deep copy of this object.

:param attributes: Attributes to be set to the returned copy. For example, obj.deepcopy(name='New name').

See also :meth:copy. The difference between deepcopy and copy is the same as with the methods having same names in the copy__ module.

__ https://docs.python.org/3/library/copy.html

Source code in src/robot/model/modelobject.py
def deepcopy(self: T, **attributes) -> T:
    """Return a deep copy of this object.

    :param attributes: Attributes to be set to the returned copy.
        For example, ``obj.deepcopy(name='New name')``.

    See also :meth:`copy`. The difference between ``deepcopy`` and
    ``copy`` is the same as with the methods having same names in
    the copy__ module.

    __ https://docs.python.org/3/library/copy.html
    """
    return copy.deepcopy(self).config(**attributes)

id property

id: str | None

Item id in format like s1-t3-k1.

See :attr:TestSuite.id <robot.model.testsuite.TestSuite.id> for more information.

id is None only in these special cases:

  • Keyword uses a placeholder for setup or teardown when a setup or teardown is not actually used.
  • With :class:~robot.model.control.If and :class:~robot.model.control.Try instances representing IF/TRY structure roots.

BaseBody

1
2
3
4
BaseBody(
    parent: BodyItemParent = None,
    items: Iterable[BodyItem | DataDict] = (),
)

Bases: ItemList[BodyItem], Generic[KW, F, W, I, T, V, R, C, B, M, E]

Base class for Body and Branches objects.

Source code in src/robot/model/body.py
def __init__(self, parent: BodyItemParent = None,
             items: 'Iterable[BodyItem|DataDict]' = ()):
    super().__init__(BodyItem, {'parent': parent}, items)

to_dicts

to_dicts() -> list[DataDict]

Return list of items converted to dictionaries.

Items are converted to dictionaries using the to_dict method, if they have it, or the built-in vars().

New in Robot Framework 6.1.

Source code in src/robot/model/itemlist.py
def to_dicts(self) -> 'list[DataDict]':
    """Return list of items converted to dictionaries.

    Items are converted to dictionaries using the ``to_dict`` method, if
    they have it, or the built-in ``vars()``.

    New in Robot Framework 6.1.
    """
    if not hasattr(self._item_class, 'to_dict'):
        return [vars(item) for item in self]
    return [item.to_dict() for item in self]    # type: ignore

filter

1
2
3
4
5
filter(
    keywords: bool | None = None,
    messages: bool | None = None,
    predicate: Callable[[T], bool] | None = None,
)

Filter body items based on type and/or custom predicate.

To include or exclude items based on types, give matching arguments True or False values. For example, to include only keywords, use body.filter(keywords=True) and to exclude messages use body.filter(messages=False). Including and excluding by types at the same time is not supported and filtering my messages is supported only if the Body object actually supports messages.

Custom predicate is a callable getting each body item as an argument that must return True/False depending on should the item be included or not.

Selected items are returned as a list and the original body is not modified.

It was earlier possible to filter also based on FOR and IF types. That support was removed in RF 5.0 because it was not considered useful in general and because adding support for all new control structures would have required extra work. To exclude all control structures, use body.filter(keywords=True, messages=True) and to only include them use body.filter(keywords=False, messages=False). For more detailed filtering it is possible to usepredicate``.

Source code in src/robot/model/body.py
def filter(self, keywords: 'bool|None' = None, messages: 'bool|None' = None,
           predicate: 'Callable[[T], bool]|None' = None):
    """Filter body items based on type and/or custom predicate.

    To include or exclude items based on types, give matching arguments
    ``True`` or ``False`` values. For example, to include only keywords,
    use ``body.filter(keywords=True)`` and to exclude messages use
    ``body.filter(messages=False)``. Including and excluding by types
    at the same time is not supported and filtering my ``messages``
    is supported only if the ``Body`` object actually supports messages.

    Custom ``predicate`` is a callable getting each body item as an argument
    that must return ``True/False`` depending on should the item be included
    or not.

    Selected items are returned as a list and the original body is not modified.

    It was earlier possible to filter also based on FOR and IF types.
    That support was removed in RF 5.0 because it was not considered useful
    in general and because adding support for all new control structures
    would have required extra work. To exclude all control structures, use
    ``body.filter(keywords=True, messages=True)`` and to only include them
    use ``body.filter(keywords=False``, messages=False)``. For more detailed
    filtering it is possible to use ``predicate``.
    """
    if messages is not None and self.message_class is KnownAtRuntime:
        raise TypeError(f"'{full_name(self)}' object does not support "
                        f"filtering by 'messages'.")
    return self._filter([(self.keyword_class, keywords),
                         (self.message_class, messages)], predicate)

flatten

flatten() -> list[BodyItem]

Return steps so that IF and TRY structures are flattened.

Basically the IF/ELSE and TRY/EXCEPT root elements are replaced with their branches. This is how they are shown in log files.

Source code in src/robot/model/body.py
def flatten(self) -> 'list[BodyItem]':
    """Return steps so that IF and TRY structures are flattened.

    Basically the IF/ELSE and TRY/EXCEPT root elements are replaced
    with their branches. This is how they are shown in log files.
    """
    roots = BodyItem.IF_ELSE_ROOT, BodyItem.TRY_EXCEPT_ROOT
    steps = []
    for item in self:
        if item.type in roots:
            item = cast('Try|If', item)
            steps.extend(item.body)
        else:
            steps.append(item)
    return steps

Body

1
2
3
4
Body(
    parent: BodyItemParent = None,
    items: Iterable[BodyItem | DataDict] = (),
)

Bases: BaseBody['Keyword', 'For', 'While', 'If', 'Try', 'Var', 'Return', 'Continue', 'Break', 'Message', 'Error']

A list-like object representing a body of a test, keyword, etc.

Body contains the keywords and other structures such as FOR loops.

Source code in src/robot/model/body.py
def __init__(self, parent: BodyItemParent = None,
             items: 'Iterable[BodyItem|DataDict]' = ()):
    super().__init__(BodyItem, {'parent': parent}, items)

to_dicts

to_dicts() -> list[DataDict]

Return list of items converted to dictionaries.

Items are converted to dictionaries using the to_dict method, if they have it, or the built-in vars().

New in Robot Framework 6.1.

Source code in src/robot/model/itemlist.py
def to_dicts(self) -> 'list[DataDict]':
    """Return list of items converted to dictionaries.

    Items are converted to dictionaries using the ``to_dict`` method, if
    they have it, or the built-in ``vars()``.

    New in Robot Framework 6.1.
    """
    if not hasattr(self._item_class, 'to_dict'):
        return [vars(item) for item in self]
    return [item.to_dict() for item in self]    # type: ignore

filter

1
2
3
4
5
filter(
    keywords: bool | None = None,
    messages: bool | None = None,
    predicate: Callable[[T], bool] | None = None,
)

Filter body items based on type and/or custom predicate.

To include or exclude items based on types, give matching arguments True or False values. For example, to include only keywords, use body.filter(keywords=True) and to exclude messages use body.filter(messages=False). Including and excluding by types at the same time is not supported and filtering my messages is supported only if the Body object actually supports messages.

Custom predicate is a callable getting each body item as an argument that must return True/False depending on should the item be included or not.

Selected items are returned as a list and the original body is not modified.

It was earlier possible to filter also based on FOR and IF types. That support was removed in RF 5.0 because it was not considered useful in general and because adding support for all new control structures would have required extra work. To exclude all control structures, use body.filter(keywords=True, messages=True) and to only include them use body.filter(keywords=False, messages=False). For more detailed filtering it is possible to usepredicate``.

Source code in src/robot/model/body.py
def filter(self, keywords: 'bool|None' = None, messages: 'bool|None' = None,
           predicate: 'Callable[[T], bool]|None' = None):
    """Filter body items based on type and/or custom predicate.

    To include or exclude items based on types, give matching arguments
    ``True`` or ``False`` values. For example, to include only keywords,
    use ``body.filter(keywords=True)`` and to exclude messages use
    ``body.filter(messages=False)``. Including and excluding by types
    at the same time is not supported and filtering my ``messages``
    is supported only if the ``Body`` object actually supports messages.

    Custom ``predicate`` is a callable getting each body item as an argument
    that must return ``True/False`` depending on should the item be included
    or not.

    Selected items are returned as a list and the original body is not modified.

    It was earlier possible to filter also based on FOR and IF types.
    That support was removed in RF 5.0 because it was not considered useful
    in general and because adding support for all new control structures
    would have required extra work. To exclude all control structures, use
    ``body.filter(keywords=True, messages=True)`` and to only include them
    use ``body.filter(keywords=False``, messages=False)``. For more detailed
    filtering it is possible to use ``predicate``.
    """
    if messages is not None and self.message_class is KnownAtRuntime:
        raise TypeError(f"'{full_name(self)}' object does not support "
                        f"filtering by 'messages'.")
    return self._filter([(self.keyword_class, keywords),
                         (self.message_class, messages)], predicate)

flatten

flatten() -> list[BodyItem]

Return steps so that IF and TRY structures are flattened.

Basically the IF/ELSE and TRY/EXCEPT root elements are replaced with their branches. This is how they are shown in log files.

Source code in src/robot/model/body.py
def flatten(self) -> 'list[BodyItem]':
    """Return steps so that IF and TRY structures are flattened.

    Basically the IF/ELSE and TRY/EXCEPT root elements are replaced
    with their branches. This is how they are shown in log files.
    """
    roots = BodyItem.IF_ELSE_ROOT, BodyItem.TRY_EXCEPT_ROOT
    steps = []
    for item in self:
        if item.type in roots:
            item = cast('Try|If', item)
            steps.extend(item.body)
        else:
            steps.append(item)
    return steps

BaseBranches

1
2
3
4
5
BaseBranches(
    branch_class: Type[IT],
    parent: BodyItemParent = None,
    items: Iterable[IT | DataDict] = (),
)

Bases: BaseBody[KW, F, W, I, T, V, R, C, B, M, E], BranchType[IT]

A list-like object representing IF and TRY branches.

Source code in src/robot/model/body.py
def __init__(self, branch_class: Type[IT],
             parent: BodyItemParent = None,
             items: 'Iterable[IT|DataDict]' = ()):
    self.branch_class = branch_class
    super().__init__(parent, items)

to_dicts

to_dicts() -> list[DataDict]

Return list of items converted to dictionaries.

Items are converted to dictionaries using the to_dict method, if they have it, or the built-in vars().

New in Robot Framework 6.1.

Source code in src/robot/model/itemlist.py
def to_dicts(self) -> 'list[DataDict]':
    """Return list of items converted to dictionaries.

    Items are converted to dictionaries using the ``to_dict`` method, if
    they have it, or the built-in ``vars()``.

    New in Robot Framework 6.1.
    """
    if not hasattr(self._item_class, 'to_dict'):
        return [vars(item) for item in self]
    return [item.to_dict() for item in self]    # type: ignore

filter

1
2
3
4
5
filter(
    keywords: bool | None = None,
    messages: bool | None = None,
    predicate: Callable[[T], bool] | None = None,
)

Filter body items based on type and/or custom predicate.

To include or exclude items based on types, give matching arguments True or False values. For example, to include only keywords, use body.filter(keywords=True) and to exclude messages use body.filter(messages=False). Including and excluding by types at the same time is not supported and filtering my messages is supported only if the Body object actually supports messages.

Custom predicate is a callable getting each body item as an argument that must return True/False depending on should the item be included or not.

Selected items are returned as a list and the original body is not modified.

It was earlier possible to filter also based on FOR and IF types. That support was removed in RF 5.0 because it was not considered useful in general and because adding support for all new control structures would have required extra work. To exclude all control structures, use body.filter(keywords=True, messages=True) and to only include them use body.filter(keywords=False, messages=False). For more detailed filtering it is possible to usepredicate``.

Source code in src/robot/model/body.py
def filter(self, keywords: 'bool|None' = None, messages: 'bool|None' = None,
           predicate: 'Callable[[T], bool]|None' = None):
    """Filter body items based on type and/or custom predicate.

    To include or exclude items based on types, give matching arguments
    ``True`` or ``False`` values. For example, to include only keywords,
    use ``body.filter(keywords=True)`` and to exclude messages use
    ``body.filter(messages=False)``. Including and excluding by types
    at the same time is not supported and filtering my ``messages``
    is supported only if the ``Body`` object actually supports messages.

    Custom ``predicate`` is a callable getting each body item as an argument
    that must return ``True/False`` depending on should the item be included
    or not.

    Selected items are returned as a list and the original body is not modified.

    It was earlier possible to filter also based on FOR and IF types.
    That support was removed in RF 5.0 because it was not considered useful
    in general and because adding support for all new control structures
    would have required extra work. To exclude all control structures, use
    ``body.filter(keywords=True, messages=True)`` and to only include them
    use ``body.filter(keywords=False``, messages=False)``. For more detailed
    filtering it is possible to use ``predicate``.
    """
    if messages is not None and self.message_class is KnownAtRuntime:
        raise TypeError(f"'{full_name(self)}' object does not support "
                        f"filtering by 'messages'.")
    return self._filter([(self.keyword_class, keywords),
                         (self.message_class, messages)], predicate)

flatten

flatten() -> list[BodyItem]

Return steps so that IF and TRY structures are flattened.

Basically the IF/ELSE and TRY/EXCEPT root elements are replaced with their branches. This is how they are shown in log files.

Source code in src/robot/model/body.py
def flatten(self) -> 'list[BodyItem]':
    """Return steps so that IF and TRY structures are flattened.

    Basically the IF/ELSE and TRY/EXCEPT root elements are replaced
    with their branches. This is how they are shown in log files.
    """
    roots = BodyItem.IF_ELSE_ROOT, BodyItem.TRY_EXCEPT_ROOT
    steps = []
    for item in self:
        if item.type in roots:
            item = cast('Try|If', item)
            steps.extend(item.body)
        else:
            steps.append(item)
    return steps