Source code for robot.libdocpkg.specbuilder

#  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
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  See the License for the specific language governing permissions and
#  limitations under the License.

import os.path

from robot.errors import DataError
from robot.running import ArgInfo, ArgumentSpec
from robot.utils import ET, ETSource

from .model import LibraryDoc, KeywordDoc
from .datatypes import EnumDoc, TypedDictDoc

[docs]class SpecDocBuilder(object):
[docs] def build(self, path): spec = self._parse_spec(path) libdoc = LibraryDoc(name=spec.get('name'), type=spec.get('type').upper(), version=spec.find('version').text or '', doc=spec.find('doc').text or '', scope=spec.get('scope'), doc_format=spec.get('format', 'ROBOT'), source=spec.get('source'), lineno=int(spec.get('lineno', -1))) libdoc.inits = self._create_keywords(spec, 'inits/init') libdoc.keywords = self._create_keywords(spec, 'keywords/kw') libdoc.data_types.update(self._create_data_types(spec)) return libdoc
def _parse_spec(self, path): if not os.path.isfile(path): raise DataError("Spec file '%s' does not exist." % path) with ETSource(path) as source: root = ET.parse(source).getroot() if root.tag != 'keywordspec': raise DataError("Invalid spec file '%s'." % path) version = root.get('specversion') if version != '3': raise DataError("Invalid spec file version '%s'. " "Robot Framework 4.0 and newer requires spec version 3." % version) return root def _create_keywords(self, spec, path): return [self._create_keyword(elem) for elem in spec.findall(path)] def _create_keyword(self, elem): # "deprecated" attribute isn't read because it is read from the doc # automatically. That should probably be changed at some point. return KeywordDoc(name=elem.get('name', ''), args=self._create_arguments(elem), doc=elem.find('doc').text or '', shortdoc=elem.find('shortdoc').text or '', tags=[t.text for t in elem.findall('tags/tag')], source=elem.get('source'), lineno=int(elem.get('lineno', -1))) def _create_arguments(self, elem): spec = ArgumentSpec() setters = { ArgInfo.POSITIONAL_ONLY: spec.positional_only.append, ArgInfo.POSITIONAL_ONLY_MARKER: lambda value: None, ArgInfo.POSITIONAL_OR_NAMED: spec.positional_or_named.append, ArgInfo.VAR_POSITIONAL: lambda value: setattr(spec, 'var_positional', value), ArgInfo.NAMED_ONLY_MARKER: lambda value: None, ArgInfo.NAMED_ONLY: spec.named_only.append, ArgInfo.VAR_NAMED: lambda value: setattr(spec, 'var_named', value), } for arg in elem.findall('arguments/arg'): name_elem = arg.find('name') if name_elem is None: continue name = name_elem.text setters[arg.get('kind')](name) default_elem = arg.find('default') if default_elem is not None: spec.defaults[name] = default_elem.text or '' type_elems = arg.findall('type') if not spec.types: spec.types = {} spec.types[name] = tuple(t.text for t in type_elems) return spec def _create_data_types(self, spec): enums = [self._create_enum_doc(dt) for dt in spec.findall('datatypes/enums/enum')] typed_dicts = [self._create_typed_dict_doc(dt) for dt in spec.findall('datatypes/typeddicts/typeddict')] return enums + typed_dicts def _create_enum_doc(self, dt): return EnumDoc(name=dt.get('name'), doc=dt.find('doc').text or '', members=[{'name': member.get('name'), 'value': member.get('value')} for member in dt.findall('members/member')]) def _create_typed_dict_doc(self, dt): items = [] for item in dt.findall('items/item'): required = item.get('required', None) if required is not None: required = True if required == 'true' else False items.append({'key': item.get('key'), 'type': item.get('type'), 'required': required}) return TypedDictDoc(name=dt.get('name'), doc=dt.find('doc').text or '', items=items)