Source code for robot.running.arguments.argumentspec

#  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.

from inspect import isclass
import re
import sys

    from typing import Union
except ImportError:
    class Union(object):

    from enum import Enum
except ImportError:    # Standard in Py 3.4+ but can be separately installed
[docs] class Enum(object): pass
from robot.utils import setter, py3to2, unicode, unic from .argumentconverter import ArgumentConverter from .argumentmapper import ArgumentMapper from .argumentresolver import ArgumentResolver from .typevalidator import TypeValidator
[docs]@py3to2 class ArgumentSpec(object): def __init__(self, name=None, type='Keyword', positional_only=None, positional_or_named=None, var_positional=None, named_only=None, var_named=None, defaults=None, types=None): = name self.type = type self.positional_only = positional_only or [] self.positional_or_named = positional_or_named or [] self.var_positional = var_positional self.named_only = named_only or [] self.var_named = var_named self.defaults = defaults or {} self.types = types @setter def types(self, types): return TypeValidator(self).validate(types) @property def positional(self): return self.positional_only + self.positional_or_named @property def minargs(self): return len([arg for arg in self.positional if arg not in self.defaults]) @property def maxargs(self): return len(self.positional) if not self.var_positional else sys.maxsize @property def argument_names(self): return (self.positional_only + self.positional_or_named + ([self.var_positional] if self.var_positional else []) + self.named_only + ([self.var_named] if self.var_named else []))
[docs] def resolve(self, arguments, variables=None, resolve_named=True, resolve_variables_until=None, dict_to_kwargs=False): resolver = ArgumentResolver(self, resolve_named, resolve_variables_until, dict_to_kwargs) positional, named = resolver.resolve(arguments, variables) if self.types or self.defaults: converter = ArgumentConverter(self, dry_run=not variables) positional, named = converter.convert(positional, named) return positional, named
[docs] def map(self, positional, named, replace_defaults=True): mapper = ArgumentMapper(self) return, named, replace_defaults)
def __iter__(self): notset = ArgInfo.NOTSET get_type = (self.types or {}).get get_default = self.defaults.get for arg in self.positional_only: yield ArgInfo(ArgInfo.POSITIONAL_ONLY, arg, get_type(arg, notset), get_default(arg, notset)) if self.positional_only: yield ArgInfo(ArgInfo.POSITIONAL_ONLY_MARKER) for arg in self.positional_or_named: yield ArgInfo(ArgInfo.POSITIONAL_OR_NAMED, arg, get_type(arg, notset), get_default(arg, notset)) if self.var_positional: yield ArgInfo(ArgInfo.VAR_POSITIONAL, self.var_positional, get_type(self.var_positional, notset)) elif self.named_only: yield ArgInfo(ArgInfo.NAMED_ONLY_MARKER) for arg in self.named_only: yield ArgInfo(ArgInfo.NAMED_ONLY, arg, get_type(arg, notset), get_default(arg, notset)) if self.var_named: yield ArgInfo(ArgInfo.VAR_NAMED, self.var_named, get_type(self.var_named, notset)) def __bool__(self): return any([self.positional_only, self.positional_or_named, self.var_positional, self.named_only, self.var_named]) def __str__(self): return ', '.join(unicode(arg) for arg in self)
[docs]@py3to2 class ArgInfo(object): NOTSET = object() POSITIONAL_ONLY = 'POSITIONAL_ONLY' POSITIONAL_ONLY_MARKER = 'POSITIONAL_ONLY_MARKER' POSITIONAL_OR_NAMED = 'POSITIONAL_OR_NAMED' VAR_POSITIONAL = 'VAR_POSITIONAL' NAMED_ONLY_MARKER = 'NAMED_ONLY_MARKER' NAMED_ONLY = 'NAMED_ONLY' VAR_NAMED = 'VAR_NAMED' def __init__(self, kind, name='', types=NOTSET, default=NOTSET): self.kind = kind = name self.types = types self.default = default @setter def types(self, typ): if not typ or typ is self.NOTSET: return tuple() if isinstance(typ, tuple): return typ if getattr(typ, '__origin__', None) is Union: return self._get_union_args(typ) return (typ,) def _get_union_args(self, union): try: return union.__args__ except AttributeError: # Python 3.5.2's typing uses __union_params__ instead # of __args__. This block can likely be safely removed # when Python 3.5 support is dropped return union.__union_params__ @property def required(self): if self.kind in (self.POSITIONAL_ONLY, self.POSITIONAL_OR_NAMED, self.NAMED_ONLY): return self.default is self.NOTSET return False @property def types_reprs(self): return [self._type_repr(t) for t in self.types] def _type_repr(self, typ): if typ is type(None): return 'None' if isclass(typ): return typ.__name__ return re.sub(r'^typing\.(.+)', r'\1', unic(typ)) @property def default_repr(self): if self.default is self.NOTSET: return None if isinstance(self.default, Enum): return return unic(self.default) def __str__(self): if self.kind == self.POSITIONAL_ONLY_MARKER: return '/' if self.kind == self.NAMED_ONLY_MARKER: return '*' ret = if self.kind == self.VAR_POSITIONAL: ret = '*' + ret elif self.kind == self.VAR_NAMED: ret = '**' + ret if self.types: ret = '%s: %s' % (ret, ' | '.join(self.types_reprs)) default_sep = ' = ' else: default_sep = '=' if self.default is not self.NOTSET: ret = '%s%s%s' % (ret, default_sep, self.default_repr) return ret