16 from ast
import literal_eval
17 from collections
import OrderedDict
18 from collections.abc
import ByteString, Container, Mapping, Sequence, Set
19 from typing
import Any, Tuple, TypeVar, Union
20 from datetime
import datetime, date, timedelta
21 from decimal
import InvalidOperation, Decimal
23 from numbers
import Integral, Real
24 from os
import PathLike
25 from pathlib
import Path, PurePath
29 from robot.utils import (eq, get_error_message, is_string, is_union, plural_or_not
as s,
30 safe_str, seq2str, type_name, type_repr, typeddict_types)
46 _converters = OrderedDict()
52 def __init__(self, used_type, custom_converters=None, languages=None):
59 cls.
_converters_converters[converter.type] = converter
60 for name
in (converter.type_name,) + converter.aliases:
61 if name
is not None and not isinstance(name, property):
71 if isinstance(type_, str):
77 if getattr(type_,
'__origin__',
None)
and type_.__origin__
is not Union:
78 type_ = type_.__origin__
80 info = custom_converters.get_converter_info(type_)
84 return cls.
_converters_converters[type_](used_type, custom_converters, languages)
85 for converter
in cls.
_converters_converters.values():
86 if converter.handles(type_):
87 return converter(used_type, custom_converters, languages)
92 handled = (cls.
typetype, cls.
abcabc)
if cls.
abcabc
else cls.
typetype
93 return isinstance(type_, type)
and issubclass(type_, handled)
95 def convert(self, name, value, explicit_type=True, strict=True, kind='Argument'):
99 return self.
_handle_error_handle_error(name, value, kind, strict=strict)
101 if not isinstance(value, str):
103 return self.
_convert_convert(value, explicit_type)
104 except ValueError
as error:
105 return self.
_handle_error_handle_error(name, value, kind, error, strict)
109 return isinstance(value, self.
used_typeused_type)
114 return isinstance(value, self.
typetype)
118 return isinstance(value, self.
value_typesvalue_types)
121 return self.
_convert_convert(value, explicit_type)
124 raise NotImplementedError
129 value_type =
'' if isinstance(value, str)
else f
' ({type_name(value)})'
131 ending = f
': {error}' if (error
and error.args)
else '.'
134 f
"{kind} '{value}'{value_type} "
135 f
"cannot be converted to {self.type_name}{ending}"
138 f
"{kind} '{name}' got value '{value}'{value_type} that "
139 f
"cannot be converted to {self.type_name}{ending}"
143 if expected
is set
and value ==
'set()':
147 value = literal_eval(value)
148 except (ValueError, SyntaxError):
150 raise ValueError(
'Invalid expression.')
151 except TypeError
as err:
152 raise ValueError(f
'Evaluating expression failed: {err}')
153 if not isinstance(value, expected):
154 raise ValueError(f
'Value is {type_name(value)}, not {expected.__name__}.')
158 types = getattr(type_hint,
'__args__', ())
162 if not types
or all(isinstance(a, TypeVar)
for a
in types):
164 if expected_count
and len(types) != expected_count:
165 raise TypeError(f
'{type_hint.__name__}[] construct used as a type hint '
166 f
'requires exactly {expected_count} nested '
167 f
'type{s(expected_count)}, got {len(types)}.')
174 value = value.replace(sep,
'')
178 @TypeConverter.register
189 value_types = property
192 return (str, int)
if issubclass(self.
used_typeused_type, int)
else (str,)
196 if isinstance(value, int):
204 members = sorted(enum.__members__)
205 matches = [m
for m
in members
if eq(m, value, ignore=
'_')]
206 if len(matches) == 1:
207 return getattr(enum, matches[0])
209 raise ValueError(f
"{self.type_name} has multiple members matching "
210 f
"'{value}'. Available: {seq2str(matches)}")
212 if issubclass(self.
used_typeused_type, int):
215 members = [f
'{m} ({getattr(enum, m)})' for m
in members]
216 raise ValueError(f
"{self.type_name} does not have member '{value}'. "
217 f
"Available: {seq2str(members)}")
222 if member.value == value:
224 values = sorted(member.value
for member
in enum)
225 raise ValueError(f
"{self.type_name} does not have value '{value}'. "
226 f
"Available: {seq2str(values)}")
229 @TypeConverter.register
233 aliases = (
'string',
'str',
'unicode')
240 if not explicit_type:
248 @TypeConverter.register
251 type_name =
'boolean'
253 value_types = (str, int, float, NoneType)
259 normalized = value.title()
260 if normalized ==
'None':
262 if normalized
in self.
languageslanguages.true_strings:
264 if normalized
in self.
languageslanguages.false_strings:
269 @TypeConverter.register
273 type_name =
'integer'
274 aliases = (
'int',
'long')
275 value_types = (str, float)
278 if value.is_integer():
280 raise ValueError(
'Conversion would lose precision.')
284 value, base = self.
_get_base_get_base(value)
286 return int(value, base)
288 if base == 10
and not explicit_type:
296 value = value.lower()
297 for prefix, base
in [(
'0x', 16), (
'0o', 8), (
'0b', 2)]:
299 parts = value.split(prefix)
300 if len(parts) == 2
and parts[0]
in (
'',
'-',
'+'):
301 return ''.join(parts), base
305 @TypeConverter.register
310 aliases = (
'double',)
311 value_types = (str, Real)
320 @TypeConverter.register
323 type_name =
'decimal'
324 value_types = (str, int, float)
329 except InvalidOperation:
336 @TypeConverter.register
341 value_types = (str, bytearray)
348 return value.encode(
'latin-1')
349 except UnicodeEncodeError
as err:
350 invalid = value[err.start:err.start+1]
351 raise ValueError(f
"Character '{invalid}' cannot be mapped to a byte.")
354 @TypeConverter.register
357 type_name =
'bytearray'
358 value_types = (str, bytes)
361 return bytearray(value)
365 return bytearray(value,
'latin-1')
366 except UnicodeEncodeError
as err:
367 invalid = value[err.start:err.start+1]
368 raise ValueError(f
"Character '{invalid}' cannot be mapped to a byte.")
371 @TypeConverter.register
374 type_name =
'datetime'
375 value_types = (str, int, float)
381 @TypeConverter.register
388 if dt.hour
or dt.minute
or dt.second
or dt.microsecond:
389 raise ValueError(
"Value is datetime, not date.")
393 @TypeConverter.register
396 type_name =
'timedelta'
397 value_types = (str, int, float)
403 @TypeConverter.register
408 value_types = (str, PurePath)
414 @TypeConverter.register
421 return type_
in (NoneType,
None)
424 if value.upper() ==
'NONE':
429 @TypeConverter.register
434 value_types = (str, Sequence)
436 def __init__(self, used_type, custom_converters=None, languages=None):
437 super().
__init__(used_type, custom_converters, languages)
448 return super().
handles(type_)
and type_
is not Tuple
451 if isinstance(value, str):
456 return self.
_convert_items_convert_items(list(value), explicit_type)
465 for i, v
in enumerate(value)]
468 @TypeConverter.register
472 value_types = (str, Sequence)
474 def __init__(self, used_type, custom_converters=None, languages=None):
475 super().
__init__(used_type, custom_converters, languages)
481 if types[-1]
is Ellipsis:
484 raise TypeError(f
'Homogenous tuple used as a type hint requires '
485 f
'exactly one nested type, got {len(types)}.')
492 return self.
_convert_items_convert_items(tuple(value), explicit_type)
502 return tuple(conv.convert(str(i), v, explicit_type, kind=
'Item')
503 for i, v
in enumerate(value))
504 if len(self.
convertersconverters) != len(value):
505 raise ValueError(f
'Expected {len(self.converters)} '
506 f
'item{s(self.converters)}, got {len(value)}.')
507 return tuple(conv.convert(i, v, explicit_type, kind=
'Item')
508 for i, (conv, v)
in enumerate(zip(self.
convertersconverters, value)))
511 @TypeConverter.register
514 value_types = (str, Mapping)
516 def __init__(self, used_type, custom_converters, languages=None):
517 super().
__init__(used_type, custom_converters, languages)
519 for n, t
in used_type.__annotations__.items()}
522 self.
required_keysrequired_keys = getattr(used_type,
'__required_keys__', frozenset())
526 return isinstance(type_, typeddict_types)
543 not_allowed.append(key)
546 value[key] = converter.convert(key, value[key], kind=
'Item')
548 error = f
'Item{s(not_allowed)} {seq2str(sorted(not_allowed))} not allowed.'
549 available = [key
for key
in self.
convertersconverters
if key
not in value]
551 error += f
' Available item{s(available)}: {seq2str(sorted(available))}'
552 raise ValueError(error)
553 missing = [key
for key
in self.
required_keysrequired_keys
if key
not in value]
555 raise ValueError(f
"Required item{s(missing)} "
556 f
"{seq2str(sorted(missing))} missing.")
560 @TypeConverter.register
564 type_name =
'dictionary'
565 aliases = (
'dict',
'map')
566 value_types = (str, Mapping)
568 def __init__(self, used_type, custom_converters=None, languages=None):
569 super().
__init__(used_type, custom_converters, languages)
579 if issubclass(self.
used_typeused_type, dict)
and not isinstance(value, dict):
591 return {convert_key(
None, k): convert_value(str(k), v)
for k, v
in value.items()}
595 return lambda name, value: value
596 return lambda name, value: converter.convert(name, value, explicit_type,
600 @TypeConverter.register
605 value_types = (str, Container)
607 def __init__(self, used_type, custom_converters=None, languages=None):
608 super().
__init__(used_type, custom_converters, languages)
617 return self.
_convert_items_convert_items(set(value), explicit_type)
625 return {self.
converterconverter.
convert(
None, v, explicit_type, kind=
'Item')
629 @TypeConverter.register
632 type_name =
'frozenset'
639 if value ==
'frozenset()':
641 return frozenset(super().
_convert(value, explicit_type))
644 @TypeConverter.register
648 def __init__(self, union, custom_converters, languages=None):
656 if isinstance(union, tuple):
658 return union.__args__
668 return is_union(type_, allow_tuple=
True)
675 if converter
and converter.no_conversion_needed(value):
684 return converter.convert(
'', value, explicit_type)
692 def __init__(self, used_type, converter_info, languages=None):
693 super().
__init__(used_type, languages=languages)
709 value_types = property
Keeps a list of languages and unifies the translations in the properties.
def _convert(self, value, explicit_type=True)
def _non_string_convert(self, value, explicit_type=True)
def _non_string_convert(self, value, explicit_type=True)
def _convert(self, value, explicit_type=True)
def _non_string_convert(self, value, explicit_type=True)
def _convert(self, value, explicit_type=True)
def __init__(self, union, custom_converters, languages=None)
def _handles_value(self, value)
def _get_types(self, union)
def _convert(self, value, explicit_type=True)
def no_conversion_needed(self, value)
def _handles_value(self, value)
def __init__(self, used_type, converter_info, languages=None)
def _convert(self, value, explicit_type=True)
def _convert(self, value, explicit_type=True)
def _convert(self, value, explicit_type=True)
def _convert(self, value, explicit_type=True)
def __init__(self, used_type, custom_converters=None, languages=None)
def __get_converter(self, converter, explicit_type, kind)
def _non_string_convert(self, value, explicit_type=True)
def _convert_items(self, value, explicit_type)
def _convert(self, value, explicit_type=True)
def _find_by_int_value(self, enum, value)
def _convert(self, value, explicit_type=True)
def _find_by_normalized_name_or_int_value(self, enum, value)
def _convert(self, value, explicit_type=True)
def _convert(self, value, explicit_type=True)
def _non_string_convert(self, value, explicit_type=True)
def _non_string_convert(self, value, explicit_type=True)
def _convert(self, value, explicit_type=True)
def _get_base(self, value)
def __init__(self, used_type, custom_converters=None, languages=None)
def _convert_items(self, value, explicit_type)
def _convert(self, value, explicit_type=True)
def no_conversion_needed(self, value)
def _non_string_convert(self, value, explicit_type=True)
def _convert(self, value, explicit_type=True)
def _convert(self, value, explicit_type=True)
def _non_string_convert(self, value, explicit_type=True)
def _convert(self, value, explicit_type=True)
def _convert_items(self, value, explicit_type)
def __init__(self, used_type, custom_converters=None, languages=None)
def _handles_value(self, value)
def _convert(self, value, explicit_type=True)
def _convert(self, value, explicit_type=True)
def _convert_items(self, value, explicit_type)
def _non_string_convert(self, value, explicit_type=True)
def __init__(self, used_type, custom_converters=None, languages=None)
def _convert(self, value, explicit_type=True)
def _non_string_convert(self, value, explicit_type=True)
def _handle_error(self, name, value, kind, error=None, strict=True)
def _get_nested_types(self, type_hint, expected_count=None)
def converter_for(cls, type_, custom_converters=None, languages=None)
def convert(self, name, value, explicit_type=True, strict=True, kind='Argument')
def __init__(self, used_type, custom_converters=None, languages=None)
def _literal_eval(self, value, expected)
def _convert(self, value, explicit_type=True)
def no_conversion_needed(self, value)
def _handles_value(self, value)
def _remove_number_separators(self, value)
def register(cls, converter)
def _convert_items(self, value)
def __init__(self, used_type, custom_converters, languages=None)
def _convert(self, value, explicit_type=True)
def no_conversion_needed(self, value)
def _non_string_convert(self, value, explicit_type=True)
def convert_time(time, result_format='number', exclude_millis=False)
Converts between supported time formats.
def convert_date(date, result_format='timestamp', exclude_millis=False, date_format=None)
Converts between supported date formats.
def get_error_message()
Returns error message of the last occurred exception.
def eq(str1, str2, ignore=(), caseless=True, spaceless=True)
def type_repr(typ)
Return string representation for types.
def is_union(item, allow_tuple=False)