Skip to content

robot.running.arguments.typeinfo

TypeInfo

1
2
3
4
5
TypeInfo(
    name: str | None = None,
    type: Any = NOT_SET,
    nested: Sequence[TypeInfo] | None = None,
)

Represents an argument type.

Normally created using the :meth:from_type_hint classmethod. With unions and parametrized types, :attr:nested contains nested types.

Values can be converted according to this type info by using the :meth:convert method.

Part of the public API starting from Robot Framework 7.0. In such usage should be imported via the :mod:robot.api package.

Source code in src/robot/running/arguments/typeinfo.py
def __init__(self, name: 'str|None' = None,
             type: Any = NOT_SET,
             nested: 'Sequence[TypeInfo]|None' = None):
    if type is NOT_SET:
        type = TYPE_NAMES.get(name.lower()) if name else None
    self.name = name
    self.type = type
    self.nested = nested

nested

1
2
3
nested(
    nested: Sequence[TypeInfo],
) -> tuple[TypeInfo, ...] | None

Nested types as a tuple of TypeInfo objects.

Used with parameterized types and unions.

Source code in src/robot/running/arguments/typeinfo.py
@setter
def nested(self, nested: 'Sequence[TypeInfo]') -> 'tuple[TypeInfo, ...]|None':
    """Nested types as a tuple of ``TypeInfo`` objects.

    Used with parameterized types and unions.
    """
    typ = self.type
    if self.is_union:
        self._validate_union(nested)
    elif nested is None:
        return None
    elif typ is None:
        return tuple(nested)
    elif typ is Literal:
        self._validate_literal(nested)
    elif not isinstance(typ, type):
        self._report_nested_error(nested)
    elif issubclass(typ, tuple):
        if nested[-1].type is Ellipsis:
            self._validate_nested_count(nested, 2, 'Homogenous tuple', offset=-1)
    elif issubclass(typ, Sequence) and not issubclass(typ, (str, bytes, bytearray)):
        self._validate_nested_count(nested, 1)
    elif issubclass(typ, Set):
        self._validate_nested_count(nested, 1)
    elif issubclass(typ, Mapping):
        self._validate_nested_count(nested, 2)
    elif typ in TYPE_NAMES.values():
        self._report_nested_error(nested)
    return tuple(nested)

from_type_hint classmethod

from_type_hint(hint: Any) -> TypeInfo

Construct a TypeInfo based on a type hint.

The type hint can be in various different formats:

  • an actual type such as int
  • a parameterized type such as list[int]
  • a union such as int | float
  • a string such as 'int', 'list[int]' or 'int | float'
  • a TypedDict (represented as a :class:TypedDictInfo)
  • a sequence of supported type hints to create a union from such as [int, float] or ('int', 'list[int]')

In special cases using a more specialized method like :meth:from_sequence may be more appropriate than using this generic method.

Source code in src/robot/running/arguments/typeinfo.py
@classmethod
def from_type_hint(cls, hint: Any) -> 'TypeInfo':
    """Construct a ``TypeInfo`` based on a type hint.

    The type hint can be in various different formats:

    - an actual type such as ``int``
    - a parameterized type such as ``list[int]``
    - a union such as ``int | float``
    - a string such as ``'int'``, ``'list[int]'`` or ``'int | float'``
    - a ``TypedDict`` (represented as a :class:`TypedDictInfo`)
    - a sequence of supported type hints to create a union from such as
      ``[int, float]`` or ``('int', 'list[int]')``

    In special cases using a more specialized method like :meth:`from_sequence`
    may be more appropriate than using this generic method.
    """
    if hint is NOT_SET:
        return cls()
    if isinstance(hint, ForwardRef):
        hint = hint.__forward_arg__
    if isinstance(hint, typeddict_types):
        return TypedDictInfo(hint.__name__, hint)
    if is_union(hint):
        nested = [cls.from_type_hint(a) for a in hint.__args__]
        return cls('Union', nested=nested)
    if hasattr(hint, '__origin__'):
        if hint.__origin__ is Literal:
            nested = [cls(repr(a) if not isinstance(a, Enum) else a.name, a)
                      for a in hint.__args__]
        elif has_args(hint):
            nested = [cls.from_type_hint(a) for a in hint.__args__]
        else:
            nested = None
        return cls(type_repr(hint, nested=False), hint.__origin__, nested)
    if isinstance(hint, str):
        return cls.from_string(hint)
    if isinstance(hint, (tuple, list)):
        return cls.from_sequence(hint)
    if isinstance(hint, type):
        return cls(type_repr(hint), hint)
    if hint is None:
        return cls('None', type(None))
    if hint is Union:    # Plain `Union` without params.
        return cls('Union')
    if hint is Any:
        return cls('Any', hint)
    if hint is Ellipsis:
        return cls('...', hint)
    return cls(str(hint))

from_type classmethod

from_type(hint: type) -> TypeInfo

Construct a TypeInfo based on an actual type.

Use :meth:from_type_hint if the type hint can also be something else than a concrete type such as a string.

Source code in src/robot/running/arguments/typeinfo.py
@classmethod
def from_type(cls, hint: type) -> 'TypeInfo':
    """Construct a ``TypeInfo`` based on an actual type.

    Use :meth:`from_type_hint` if the type hint can also be something else
    than a concrete type such as a string.
    """
    return cls(type_repr(hint), hint)

from_string classmethod

from_string(hint: str) -> TypeInfo

Construct a TypeInfo based on a string.

In addition to just types names or their aliases like int or integer, supports also parameterized types like list[int] as well as unions like int | float.

Use :meth:from_type_hint if the type hint can also be something else than a string such as an actual type.

Source code in src/robot/running/arguments/typeinfo.py
@classmethod
def from_string(cls, hint: str) -> 'TypeInfo':
    """Construct a ``TypeInfo`` based on a string.

    In addition to just types names or their aliases like ``int`` or ``integer``,
    supports also parameterized types like ``list[int]`` as well as unions like
    ``int | float``.

    Use :meth:`from_type_hint` if the type hint can also be something else
    than a string such as an actual type.
    """
    # Needs to be imported here due to cyclic dependency.
    from .typeinfoparser import TypeInfoParser
    try:
        return TypeInfoParser(hint).parse()
    except ValueError as err:
        raise DataError(str(err))

from_sequence classmethod

from_sequence(sequence: tuple | list) -> TypeInfo

Construct a TypeInfo based on a sequence of types.

Types can be actual types, strings, or anything else accepted by :meth:from_type_hint. If the sequence contains just one type, a TypeInfo created based on it is returned. If there are more types, the returned TypeInfo represents a union. Using an empty sequence is an error.

Use :meth:from_type_hint if other types than sequences need to supported.

Source code in src/robot/running/arguments/typeinfo.py
@classmethod
def from_sequence(cls, sequence: 'tuple|list') -> 'TypeInfo':
    """Construct a ``TypeInfo`` based on a sequence of types.

    Types can be actual types, strings, or anything else accepted by
    :meth:`from_type_hint`. If the sequence contains just one type,
    a ``TypeInfo`` created based on it is returned. If there are more
    types, the returned ``TypeInfo`` represents a union. Using an empty
    sequence is an error.

    Use :meth:`from_type_hint` if other types than sequences need to
    supported.
    """
    infos = []
    for typ in sequence:
        info = cls.from_type_hint(typ)
        if info.is_union:
            infos.extend(info.nested)
        else:
            infos.append(info)
    if len(infos) == 1:
        return infos[0]
    return cls('Union', nested=infos)

convert

1
2
3
4
5
6
7
8
9
convert(
    value: Any,
    name: str | None = None,
    custom_converters: (
        CustomArgumentConverters | dict | None
    ) = None,
    languages: LanguagesLike = None,
    kind: str = "Argument",
)

Convert value based on type information this TypeInfo contains.

:param value: Value to convert. :param name: Name of the argument or other thing to convert. Used only for error reporting. :param custom_converters: Custom argument converters. :param languages: Language configuration. During execution, uses the current language configuration by default. :param kind: Type of the thing to be converted. Used only for error reporting. :raises: TypeError if there is no converter for this type or ValueError is conversion fails. :return: Converted value.

Source code in src/robot/running/arguments/typeinfo.py
def convert(self, value: Any,
            name: 'str|None' = None,
            custom_converters: 'CustomArgumentConverters|dict|None' = None,
            languages: 'LanguagesLike' = None,
            kind: str = 'Argument'):
    """Convert ``value`` based on type information this ``TypeInfo`` contains.

    :param value: Value to convert.
    :param name: Name of the argument or other thing to convert.
        Used only for error reporting.
    :param custom_converters: Custom argument converters.
    :param languages: Language configuration. During execution, uses the
        current language configuration by default.
    :param kind: Type of the thing to be converted.
        Used only for error reporting.
    :raises: ``TypeError`` if there is no converter for this type or
        ``ValueError`` is conversion fails.
    :return: Converted value.
    """
    if isinstance(custom_converters, dict):
        custom_converters = CustomArgumentConverters.from_dict(custom_converters)
    if not languages and EXECUTION_CONTEXTS.current:
        languages = EXECUTION_CONTEXTS.current.languages
    elif not isinstance(languages, Languages):
        languages = Languages(languages)
    converter = TypeConverter.converter_for(self, custom_converters, languages)
    if not converter:
        raise TypeError(f"No converter found for '{self}'.")
    return converter.convert(value, name, kind)

TypedDictInfo

TypedDictInfo(name: str, type: type)

Bases: TypeInfo

Represents TypedDict used as an argument.

Source code in src/robot/running/arguments/typeinfo.py
def __init__(self, name: str, type: type):
    super().__init__(name, type)
    type_hints = self._get_type_hints(type)
    # __required_keys__ is new in Python 3.9.
    self.required = getattr(type, '__required_keys__', frozenset())
    if sys.version_info < (3, 11):
        self._handle_typing_extensions_required_and_not_required(type_hints)
    self.annotations = {name: TypeInfo.from_type_hint(hint)
                        for name, hint in type_hints.items()}

nested

1
2
3
nested(
    nested: Sequence[TypeInfo],
) -> tuple[TypeInfo, ...] | None

Nested types as a tuple of TypeInfo objects.

Used with parameterized types and unions.

Source code in src/robot/running/arguments/typeinfo.py
@setter
def nested(self, nested: 'Sequence[TypeInfo]') -> 'tuple[TypeInfo, ...]|None':
    """Nested types as a tuple of ``TypeInfo`` objects.

    Used with parameterized types and unions.
    """
    typ = self.type
    if self.is_union:
        self._validate_union(nested)
    elif nested is None:
        return None
    elif typ is None:
        return tuple(nested)
    elif typ is Literal:
        self._validate_literal(nested)
    elif not isinstance(typ, type):
        self._report_nested_error(nested)
    elif issubclass(typ, tuple):
        if nested[-1].type is Ellipsis:
            self._validate_nested_count(nested, 2, 'Homogenous tuple', offset=-1)
    elif issubclass(typ, Sequence) and not issubclass(typ, (str, bytes, bytearray)):
        self._validate_nested_count(nested, 1)
    elif issubclass(typ, Set):
        self._validate_nested_count(nested, 1)
    elif issubclass(typ, Mapping):
        self._validate_nested_count(nested, 2)
    elif typ in TYPE_NAMES.values():
        self._report_nested_error(nested)
    return tuple(nested)

from_type_hint classmethod

from_type_hint(hint: Any) -> TypeInfo

Construct a TypeInfo based on a type hint.

The type hint can be in various different formats:

  • an actual type such as int
  • a parameterized type such as list[int]
  • a union such as int | float
  • a string such as 'int', 'list[int]' or 'int | float'
  • a TypedDict (represented as a :class:TypedDictInfo)
  • a sequence of supported type hints to create a union from such as [int, float] or ('int', 'list[int]')

In special cases using a more specialized method like :meth:from_sequence may be more appropriate than using this generic method.

Source code in src/robot/running/arguments/typeinfo.py
@classmethod
def from_type_hint(cls, hint: Any) -> 'TypeInfo':
    """Construct a ``TypeInfo`` based on a type hint.

    The type hint can be in various different formats:

    - an actual type such as ``int``
    - a parameterized type such as ``list[int]``
    - a union such as ``int | float``
    - a string such as ``'int'``, ``'list[int]'`` or ``'int | float'``
    - a ``TypedDict`` (represented as a :class:`TypedDictInfo`)
    - a sequence of supported type hints to create a union from such as
      ``[int, float]`` or ``('int', 'list[int]')``

    In special cases using a more specialized method like :meth:`from_sequence`
    may be more appropriate than using this generic method.
    """
    if hint is NOT_SET:
        return cls()
    if isinstance(hint, ForwardRef):
        hint = hint.__forward_arg__
    if isinstance(hint, typeddict_types):
        return TypedDictInfo(hint.__name__, hint)
    if is_union(hint):
        nested = [cls.from_type_hint(a) for a in hint.__args__]
        return cls('Union', nested=nested)
    if hasattr(hint, '__origin__'):
        if hint.__origin__ is Literal:
            nested = [cls(repr(a) if not isinstance(a, Enum) else a.name, a)
                      for a in hint.__args__]
        elif has_args(hint):
            nested = [cls.from_type_hint(a) for a in hint.__args__]
        else:
            nested = None
        return cls(type_repr(hint, nested=False), hint.__origin__, nested)
    if isinstance(hint, str):
        return cls.from_string(hint)
    if isinstance(hint, (tuple, list)):
        return cls.from_sequence(hint)
    if isinstance(hint, type):
        return cls(type_repr(hint), hint)
    if hint is None:
        return cls('None', type(None))
    if hint is Union:    # Plain `Union` without params.
        return cls('Union')
    if hint is Any:
        return cls('Any', hint)
    if hint is Ellipsis:
        return cls('...', hint)
    return cls(str(hint))

from_type classmethod

from_type(hint: type) -> TypeInfo

Construct a TypeInfo based on an actual type.

Use :meth:from_type_hint if the type hint can also be something else than a concrete type such as a string.

Source code in src/robot/running/arguments/typeinfo.py
@classmethod
def from_type(cls, hint: type) -> 'TypeInfo':
    """Construct a ``TypeInfo`` based on an actual type.

    Use :meth:`from_type_hint` if the type hint can also be something else
    than a concrete type such as a string.
    """
    return cls(type_repr(hint), hint)

from_string classmethod

from_string(hint: str) -> TypeInfo

Construct a TypeInfo based on a string.

In addition to just types names or their aliases like int or integer, supports also parameterized types like list[int] as well as unions like int | float.

Use :meth:from_type_hint if the type hint can also be something else than a string such as an actual type.

Source code in src/robot/running/arguments/typeinfo.py
@classmethod
def from_string(cls, hint: str) -> 'TypeInfo':
    """Construct a ``TypeInfo`` based on a string.

    In addition to just types names or their aliases like ``int`` or ``integer``,
    supports also parameterized types like ``list[int]`` as well as unions like
    ``int | float``.

    Use :meth:`from_type_hint` if the type hint can also be something else
    than a string such as an actual type.
    """
    # Needs to be imported here due to cyclic dependency.
    from .typeinfoparser import TypeInfoParser
    try:
        return TypeInfoParser(hint).parse()
    except ValueError as err:
        raise DataError(str(err))

from_sequence classmethod

from_sequence(sequence: tuple | list) -> TypeInfo

Construct a TypeInfo based on a sequence of types.

Types can be actual types, strings, or anything else accepted by :meth:from_type_hint. If the sequence contains just one type, a TypeInfo created based on it is returned. If there are more types, the returned TypeInfo represents a union. Using an empty sequence is an error.

Use :meth:from_type_hint if other types than sequences need to supported.

Source code in src/robot/running/arguments/typeinfo.py
@classmethod
def from_sequence(cls, sequence: 'tuple|list') -> 'TypeInfo':
    """Construct a ``TypeInfo`` based on a sequence of types.

    Types can be actual types, strings, or anything else accepted by
    :meth:`from_type_hint`. If the sequence contains just one type,
    a ``TypeInfo`` created based on it is returned. If there are more
    types, the returned ``TypeInfo`` represents a union. Using an empty
    sequence is an error.

    Use :meth:`from_type_hint` if other types than sequences need to
    supported.
    """
    infos = []
    for typ in sequence:
        info = cls.from_type_hint(typ)
        if info.is_union:
            infos.extend(info.nested)
        else:
            infos.append(info)
    if len(infos) == 1:
        return infos[0]
    return cls('Union', nested=infos)

convert

1
2
3
4
5
6
7
8
9
convert(
    value: Any,
    name: str | None = None,
    custom_converters: (
        CustomArgumentConverters | dict | None
    ) = None,
    languages: LanguagesLike = None,
    kind: str = "Argument",
)

Convert value based on type information this TypeInfo contains.

:param value: Value to convert. :param name: Name of the argument or other thing to convert. Used only for error reporting. :param custom_converters: Custom argument converters. :param languages: Language configuration. During execution, uses the current language configuration by default. :param kind: Type of the thing to be converted. Used only for error reporting. :raises: TypeError if there is no converter for this type or ValueError is conversion fails. :return: Converted value.

Source code in src/robot/running/arguments/typeinfo.py
def convert(self, value: Any,
            name: 'str|None' = None,
            custom_converters: 'CustomArgumentConverters|dict|None' = None,
            languages: 'LanguagesLike' = None,
            kind: str = 'Argument'):
    """Convert ``value`` based on type information this ``TypeInfo`` contains.

    :param value: Value to convert.
    :param name: Name of the argument or other thing to convert.
        Used only for error reporting.
    :param custom_converters: Custom argument converters.
    :param languages: Language configuration. During execution, uses the
        current language configuration by default.
    :param kind: Type of the thing to be converted.
        Used only for error reporting.
    :raises: ``TypeError`` if there is no converter for this type or
        ``ValueError`` is conversion fails.
    :return: Converted value.
    """
    if isinstance(custom_converters, dict):
        custom_converters = CustomArgumentConverters.from_dict(custom_converters)
    if not languages and EXECUTION_CONTEXTS.current:
        languages = EXECUTION_CONTEXTS.current.languages
    elif not isinstance(languages, Languages):
        languages = Languages(languages)
    converter = TypeConverter.converter_for(self, custom_converters, languages)
    if not converter:
        raise TypeError(f"No converter found for '{self}'.")
    return converter.convert(value, name, kind)