Skip to content
Snippets Groups Projects
entity.py 5.91 KiB
Newer Older
"""
  Copyright (C) 2010 CNRS

  Author: Florent Lamiraux
"""
import wrap, signal_base, new
entityClassNameList = []
if 'display' not in globals().keys():
    def display(s):
        print(s)

def commandMethod(name, docstring) :
    def method(self, *arg):
        return wrap.entity_execute_command(self.obj, name, arg)
def initEntity(self, name):
    """
    Common constructor of Entity classes
    """
    Entity.__init__(self, self.className, name)
    if not self.__class__.commandCreated:
        # Get list of commands of the Entity object
        commands = wrap.entity_list_commands(self.obj)
        # for each command, add a method with the name of the command
        for command in commands:
            docstring = wrap.entity_get_command_docstring(self.obj, command)
            setattrpath(self.__class__, command, commandMethod(command, docstring))
        self.__class__.commandCreated = True


class PyEntityFactoryClass(type):
    """
    The class build dynamically a new class type, and return the reference
    on the class-type object. The class type is not added to any context.
    """
    def __new__(factory, className ):
        EntityClass = type.__new__(factory, className, (Entity,), {})
        EntityClass.className = className
        EntityClass.__init__ = initEntity
        EntityClass.commandCreated = False
        return EntityClass

def PyEntityFactory( className, context ):
    """
    Build a new class type by calling the factory, and add it
    to the given context.
    """
    EntityClass = PyEntityFactoryClass( className )
    context[ className ] = EntityClass
    return EntityClass

def updateEntityClasses(dictionary):
    """
    For all c++entity types that are not in the pyentity class list (entityClassNameList)
    run the factory and store the new type in the given context (dictionary).
    """
    cxx_entityList = wrap.factory_get_entity_class_list()
    for e in filter(lambda x: not x in entityClassNameList, cxx_entityList):
        # Store new class in dictionary with class name
        PyEntityFactory( e,dictionary )
        # Store class name in local list
        entityClassNameList.append(e)
    """
    This class binds dynamicgraph::Entity C++ class
    """
    obj = None
florent's avatar
florent committed
    def __init__(self, className, instanceName):
        """
        Constructor: if not called by a child class, create and store a pointer
        to a C++ Entity object.
        """
        object.__setattr__(self, 'obj', wrap.create_entity(className, instanceName) )
        return wrap.entity_get_name(self.obj)
    def __str__(self) :
        return wrap.display_entity(self.obj)

    def signal (self, name) :
        """
        Get a signal of the entity from signal name
        """
        signalPt = wrap.entity_get_signal(self.obj, name)
        return signal_base.SignalBase(name = "", obj = signalPt)
    def displaySignals(self) :
Nicolas Mansard's avatar
Nicolas Mansard committed
        Print the list of signals into standard output: temporary.
        display ("--- <" +  self.name + "> signal list: ")
            display("    |-- <" + str(s))
        display("    `-- <" + str(signals[-1]))
Nicolas Mansard's avatar
Nicolas Mansard committed
        """
        Return the list of signals
Nicolas Mansard's avatar
Nicolas Mansard committed
        """
        sl = wrap.entity_list_signals(self.obj)
Florent Lamiraux's avatar
Florent Lamiraux committed
        return map(lambda pyObj: signal_base.SignalBase(obj=pyObj), sl)
Nicolas Mansard's avatar
Nicolas Mansard committed
        """
        Return the list of commands.
        """
        return wrap.entity_list_commands(self.obj)

    def globalHelp(self):
Nicolas Mansard's avatar
Nicolas Mansard committed
        """
        Print a short description of each command.
        """
        for cstr in self.commands():
            ctitle=cstr+':'
            for i in range(len(cstr),15):
                ctitle+=' '
            for docstr in wrap.entity_get_command_docstring(self.obj,cstr).split('\n'):
                if (len(docstr)>0) and (not docstr.isspace()):
                    display(ctitle+"\t"+docstr)
                    break

    def help( self,comm=None ):
Nicolas Mansard's avatar
Nicolas Mansard committed
        """
        With no arg, print the global help. With arg the name of
        a specific command, print the help associated to the command.
        """
        if comm is None:
            self.globalHelp()
        else:
            display(comm+":\n"+wrap.entity_get_command_docstring(self.obj,comm))
        except:
            object.__getattr__(self, name)
    def boundNewCommand(self,cmdName):
        """
        At construction, all existing commands are bound directly in the class.
        This method enables to bound new commands dynamically. These new bounds
        are not made with the class, but directly with the object instance.
        """
        if (cmdName in self.__dict__) | (cmdName in self.__class__.__dict__):
            print "Warning: command ",cmdName," will overwrite an object attribute."
        docstring = wrap.entity_get_command_docstring(self.obj, cmdName)
        cmd = commandMethod(cmdName,docstring)
        # Limitation (todo): does not handle for path attribute name (see setattrpath).
        setattr(self,cmdName,new.instancemethod( cmd, self,self.__class__))

    def boundAllNewCommands(self):
        """
        For all commands that are not attribute of the object instance nor of the
        class, a new attribute of the instance is created to bound the command.
        """
        cmdList = wrap.entity_list_commands(self.obj)
        cmdList = filter(lambda x: not x in self.__dict__, cmdList)
        cmdList = filter(lambda x: not x in self.__class__.__dict__, cmdList)
        for cmd in cmdList:
            self.boundNewCommand( cmd )

   # Script short-cuts: don't use this syntaxt in python coding,
    # use it for debuging online only!
    @property
    def sigs(self):
        self.displaySignals()