1# 2# Copyright OpenEmbedded Contributors 3# 4# SPDX-License-Identifier: GPL-2.0-only 5# 6"""OpenEmbedded variable typing support 7 8Types are defined in the metadata by name, using the 'type' flag on a 9variable. Other flags may be utilized in the construction of the types. See 10the arguments of the type's factory for details. 11""" 12 13import inspect 14import oe.types as types 15from collections.abc import Callable 16 17available_types = {} 18 19class MissingFlag(TypeError): 20 """A particular flag is required to construct the type, but has not been 21 provided.""" 22 def __init__(self, flag, type): 23 self.flag = flag 24 self.type = type 25 TypeError.__init__(self) 26 27 def __str__(self): 28 return "Type '%s' requires flag '%s'" % (self.type, self.flag) 29 30def factory(var_type): 31 """Return the factory for a specified type.""" 32 if var_type is None: 33 raise TypeError("No type specified. Valid types: %s" % 34 ', '.join(available_types)) 35 try: 36 return available_types[var_type] 37 except KeyError: 38 raise TypeError("Invalid type '%s':\n Valid types: %s" % 39 (var_type, ', '.join(available_types))) 40 41def create(value, var_type, **flags): 42 """Create an object of the specified type, given the specified flags and 43 string value.""" 44 obj = factory(var_type) 45 objflags = {} 46 for flag in obj.flags: 47 if flag not in flags: 48 if flag not in obj.optflags: 49 raise MissingFlag(flag, var_type) 50 else: 51 objflags[flag] = flags[flag] 52 53 return obj(value, **objflags) 54 55def get_callable_args(obj): 56 """Grab all but the first argument of the specified callable, returning 57 the list, as well as a list of which of the arguments have default 58 values.""" 59 if type(obj) is type: 60 obj = obj.__init__ 61 62 sig = inspect.signature(obj) 63 args = list(sig.parameters.keys()) 64 defaults = list(s for s in sig.parameters.keys() if sig.parameters[s].default != inspect.Parameter.empty) 65 flaglist = [] 66 if args: 67 if len(args) > 1 and args[0] == 'self': 68 args = args[1:] 69 flaglist.extend(args) 70 71 optional = set() 72 if defaults: 73 optional |= set(flaglist[-len(defaults):]) 74 return flaglist, optional 75 76def factory_setup(name, obj): 77 """Prepare a factory for use.""" 78 args, optional = get_callable_args(obj) 79 extra_args = args[1:] 80 if extra_args: 81 obj.flags, optional = extra_args, optional 82 obj.optflags = set(optional) 83 else: 84 obj.flags = obj.optflags = () 85 86 if not hasattr(obj, 'name'): 87 obj.name = name 88 89def register(name, factory): 90 """Register a type, given its name and a factory callable. 91 92 Determines the required and optional flags from the factory's 93 arguments.""" 94 factory_setup(name, factory) 95 available_types[factory.name] = factory 96 97 98# Register all our included types 99for name in dir(types): 100 if name.startswith('_'): 101 continue 102 103 obj = getattr(types, name) 104 if not isinstance(obj, Callable): 105 continue 106 107 register(name, obj) 108