1from collections import OrderedDict
2import inspect
3
4def _set_cls_value(kind, name, value):
5    curframe = inspect.currentframe()
6    try:
7        calframe = inspect.getouterframes(curframe, 3)
8        try:
9            cls_locals =  calframe[2][0].f_locals
10            if not kind in cls_locals:
11               cls_locals[kind] = OrderedDict()
12            cls_locals[kind][name] = value
13        finally:
14            del calframe
15    finally:
16        del curframe
17
18
19def add_level(name, classname, doc = "(no documentation available yet)", default=False):
20    """ Defines an abstraction level for a component.
21
22    Abstraction levels are predefined subsets of the component output or
23    input, defining a particular functional level for your component.
24
25    .. note::
26        Two special level names are reserved: `all` and `default`. You can
27        not use them.
28
29    :param name: name of the level
30    :param classpath: classpath (ie, module path + classname) that implements
31                      the level, or None to use the current class.
32    :param doc: short description of the level.
33    """
34    if name in ["all", "default"]:
35        raise NameError("%s is a reserved level name. You can not use it." % name)
36
37    _set_cls_value('_levels', name, (classname, doc, default))
38
39
40def add_data(name, default_value, type = "", doc = "(no documentation available yet)", level = "all"):
41    """
42    Defines a new data field for this component, either for export (sensors)
43    or for import (actuators).
44
45    .. note::
46        Several fields with the same name may be present if they belong to
47        different 'abstraction levels'.
48
49    :param name: name of the field
50    :param default_value: initial value of the field
51    :param type: indicative type value, currently only used for documentation
52    :param doc: description of the field
53    :param level: (default: `all`) abstraction level this field belong to.
54                  Only useful when levels are defined for the component
55                  with `add_level` statements.
56
57    """
58
59    if isinstance(level, str) and level is not "all":
60        level = [level]
61    _set_cls_value('_data_fields', name, (default_value, type, doc, level))
62
63def add_property(python_name, default_value, name, type = "", doc = "(no documentation available yet)"):
64    """ Add a property to the current class of component
65
66    :param python_name: name of the Python variable. It will be
67                        dynamically added to the component Python
68                        script.
69    :param default_value: the default value
70    :param string name: the name of the property. If used in
71                        the Blender logic bricks, it must match the
72                        Blender name.
73    :param type: type of the property, for documentation
74    :param doc: description of the property.
75    """
76
77    _set_cls_value('_properties', name, (default_value, type, doc, python_name))
78