Source code for robot.libdocpkg.datatypes

#  Copyright 2008-2015 Nokia Networks
#  Copyright 2016-     Robot Framework Foundation
#
#  Licensed under the Apache License, Version 2.0 (the "License");
#  you may not use this file except in compliance with the License.
#  You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License.

from inspect import isclass
from enum import Enum

from robot.utils import getdoc, Sortable, typeddict_types, type_name
from robot.running import TypeConverter

from .standardtypes import STANDARD_TYPE_DOCS


EnumType = type(Enum)


[docs] class TypeDoc(Sortable): ENUM = 'Enum' TYPED_DICT = 'TypedDict' CUSTOM = 'Custom' STANDARD = 'Standard' def __init__(self, type, name, doc, accepts=(), usages=None, members=None, items=None): self.type = type self.name = name self.doc = doc or '' # doc parsed from XML can be None. self.accepts = [type_name(t) if not isinstance(t, str) else t for t in accepts] self.usages = usages or [] # Enum members and TypedDict items are used only with appropriate types. self.members = members self.items = items @property def _sort_key(self): return self.name.lower()
[docs] @classmethod def for_type(cls, type_info, converters): if isinstance(type_info.type, EnumType): return cls.for_enum(type_info.type) if isinstance(type_info.type, typeddict_types): return cls.for_typed_dict(type_info.type) converter = TypeConverter.converter_for(type_info, converters) if not converter: return None elif not converter.type: return cls(cls.CUSTOM, converter.type_name, converter.doc, converter.value_types) else: # Get `type_name` from class, not from instance, to get the original # name with generics like `list[int]` that override it in instance. return cls(cls.STANDARD, type(converter).type_name, STANDARD_TYPE_DOCS[converter.type], converter.value_types)
[docs] @classmethod def for_enum(cls, enum): accepts = (str, int) if issubclass(enum, int) else (str,) return cls(cls.ENUM, enum.__name__, getdoc(enum), accepts, members=[EnumMember(name, str(member.value)) for name, member in enum.__members__.items()])
[docs] @classmethod def for_typed_dict(cls, typed_dict): items = [] required_keys = list(getattr(typed_dict, '__required_keys__', [])) optional_keys = list(getattr(typed_dict, '__optional_keys__', [])) for key, value in typed_dict.__annotations__.items(): typ = value.__name__ if isclass(value) else str(value) required = key in required_keys if required_keys or optional_keys else None items.append(TypedDictItem(key, typ, required)) return cls(cls.TYPED_DICT, typed_dict.__name__, getdoc(typed_dict), accepts=(str, 'Mapping'), items=items)
[docs] def to_dictionary(self): data = { 'type': self.type, 'name': self.name, 'doc': self.doc, 'usages': self.usages, 'accepts': self.accepts } if self.members is not None: data['members'] = [m.to_dictionary() for m in self.members] if self.items is not None: data['items'] = [i.to_dictionary() for i in self.items] return data
[docs] class TypedDictItem: def __init__(self, key, type, required=None): self.key = key self.type = type self.required = required
[docs] def to_dictionary(self): return {'key': self.key, 'type': self.type, 'required': self.required}
[docs] class EnumMember: def __init__(self, name, value): self.name = name self.value = value
[docs] def to_dictionary(self): return {'name': self.name, 'value': self.value}