""" Copyright (C) 2010 CNRS Author: Florent Lamiraux """ import wrap, signal_base, new from attrpath import setattrpath 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) method.__doc__ = docstring return method 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) class Entity (object) : """ This class binds dynamicgraph::Entity C++ class """ obj = None 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) ) @property def name(self) : 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) : """ Print the list of signals into standard output: temporary. """ signals = self.signals() display ("--- <" + self.name + "> signal list: ") for s in signals[:-1]: display(" |-- <" + str(s)) display(" `-- <" + str(signals[-1])) def signals(self) : """ Return the list of signals """ sl = wrap.entity_list_signals(self.obj) return map(lambda pyObj: signal_base.SignalBase(obj=pyObj), sl) def commands(self): """ Return the list of commands. """ return wrap.entity_list_commands(self.obj) def globalHelp(self): """ 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 ): """ 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)) def __getattr__(self, name): try: return self.signal(name) 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()