blob: 139f33369137753a19f47f63c0f3c7ee5ad754f1 [file] [log] [blame]
"""OpenEmbedded variable typing support
Types are defined in the metadata by name, using the 'type' flag on a
variable. Other flags may be utilized in the construction of the types. See
the arguments of the type's factory for details.
"""
import inspect
import types
available_types = {}
class MissingFlag(TypeError):
"""A particular flag is required to construct the type, but has not been
provided."""
def __init__(self, flag, type):
self.flag = flag
self.type = type
TypeError.__init__(self)
def __str__(self):
return "Type '%s' requires flag '%s'" % (self.type, self.flag)
def factory(var_type):
"""Return the factory for a specified type."""
if var_type is None:
raise TypeError("No type specified. Valid types: %s" %
', '.join(available_types))
try:
return available_types[var_type]
except KeyError:
raise TypeError("Invalid type '%s':\n Valid types: %s" %
(var_type, ', '.join(available_types)))
def create(value, var_type, **flags):
"""Create an object of the specified type, given the specified flags and
string value."""
obj = factory(var_type)
objflags = {}
for flag in obj.flags:
if flag not in flags:
if flag not in obj.optflags:
raise MissingFlag(flag, var_type)
else:
objflags[flag] = flags[flag]
return obj(value, **objflags)
def get_callable_args(obj):
"""Grab all but the first argument of the specified callable, returning
the list, as well as a list of which of the arguments have default
values."""
if type(obj) is type:
obj = obj.__init__
args, varargs, keywords, defaults = inspect.getargspec(obj)
flaglist = []
if args:
if len(args) > 1 and args[0] == 'self':
args = args[1:]
flaglist.extend(args)
optional = set()
if defaults:
optional |= set(flaglist[-len(defaults):])
return flaglist, optional
def factory_setup(name, obj):
"""Prepare a factory for use."""
args, optional = get_callable_args(obj)
extra_args = args[1:]
if extra_args:
obj.flags, optional = extra_args, optional
obj.optflags = set(optional)
else:
obj.flags = obj.optflags = ()
if not hasattr(obj, 'name'):
obj.name = name
def register(name, factory):
"""Register a type, given its name and a factory callable.
Determines the required and optional flags from the factory's
arguments."""
factory_setup(name, factory)
available_types[factory.name] = factory
# Register all our included types
for name in dir(types):
if name.startswith('_'):
continue
obj = getattr(types, name)
if not callable(obj):
continue
register(name, obj)