Skip to content
Snippets Groups Projects
Commit a46e2f94 authored by Nicolas Mansard's avatar Nicolas Mansard Committed by Nicolas Mansard
Browse files

Merge branch 'topic/pathName' into topic/jrl-mal

parents aabd39ac b2c500ac
No related branches found
No related tags found
No related merge requests found
......@@ -106,6 +106,7 @@ INSTALL(TARGETS ${PYTHON_MODULE}
SET (PYTHON_SOURCES
dynamic_graph/__init__.py
dynamic_graph/attrpath.py
dynamic_graph/entity.py
dynamic_graph/signal_base.py
dynamic_graph/matlab.py
......
# This module define the three functions:
# - getattrpath
# - setattrpath
# - existattrpath
# that work similarly as the get/setattr, but given path ("a.b.c.d")
# in input. Consider the following example:
# >>> setattrpath( e.__class__,"a.b.c.d",fun)
# with fun a function (self,*arg). Then, it is next possible to launch
# >>> e.a.b.c.d( ...)
# as if it was a classical member function of e.
class CommandPath(object):
"""
This class is only defined to implement a path of attribute
to store entity commands. It has no members except those automatically
defined at run time (which should be CommandPath or functions).
"""
mother=None
def __getattr__(self,name):
privateName=name+'_obj'
if privateName in self.__dict__:
obj=getattr(self,privateName)
obj.mother=self.mother
return obj
return object.__getattr__(self,name)
def createCommandModule( target,name ):
def createGetter( name ):
def __( self ):
obj = getattr(self,name)
obj.mother=self
return obj
return __
privateName = name+'_obj'
setattr( target,privateName, CommandPath() )
module = getattr( target,privateName )
if not isinstance(target,CommandPath) :
setattr( target,name, property(createGetter(privateName)) )
class CommandLauncher(object):
"""
"""
mother=None
fun=None
def __init__(self,fun): self.fun=fun
def __call__(self,*arg):
return self.fun(self.mother,*arg)
def createCommandLauncher( target,name,fun ):
if isinstance(target,CommandPath) :
privateName = name+'_obj'
setattr( target,privateName, CommandLauncher(fun) )
else:
setattr( target,name,fun )
def setattrpath( target,path,attribute ):
"""
Create in target an new attribute with value path (available at
target.path1. ... .pathn).
"""
pathk=target
read=True
if type(path)==type(str()): path=path.split('.')
for tokenk in path[0:-1]:
if (not read) | (tokenk not in pathk.__dict__):
read=False
createCommandModule(pathk,tokenk)
pathk = getattr(pathk,tokenk+"_obj")
if callable(attribute):
createCommandLauncher( pathk,path[-1],attribute )
else:
print "Should not happen"
setattr(pathk,path[-1],attribute )
def getattrpath( target,path ):
"""
Get in target the value located at path (available at
target.path1. ... .pathn).
"""
pathk=target
if type(path)==type(str()): path=path.split('.')
for tokenk in path:
privateName=tokenk+"_obj"
if (privateName in pathk.__dict__): pathk = getattr(pathk,privateName)
else:
if ( tokenk in pathk.__dict__): pathk = getattr(pathk,tokenk)
else:
raise Exception('Path does not exist -- while accessing "'+tokenk+'" in '+'.'.join(path))
return pathk
def existattrpath( target,path ):
"""
Check for the existence in target of a value located at path (available at
target.path1. ... .pathn).
"""
pathk=target
if type(path)==type(str()): path=path.split('.')
for tokenk in path[0:-1]:
print 'check ',tokenk
privateName=tokenk+"_obj"
if (privateName not in pathk.__dict__):
return False
pathk = getattr(pathk,privateName)
name=path[-1]
privateName=name+"_obj"
return (name in pathk.__dict__)|(privateName in pathk.__dict__)
"""
Copyright (C) 2010 CNRS
Author: Florent Lamiraux
Author: Florent Lamiraux, Nicolas Mansard
"""
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)
setattr(self.__class__, command, commandMethod(command, docstring))
self.__class__.commandCreated = True
# --- FACTORY ------------------------------------------------------------------
# --- FACTORY ------------------------------------------------------------------
# --- FACTORY ------------------------------------------------------------------
class PyEntityFactoryClass(type):
"""
......@@ -41,7 +22,7 @@ class PyEntityFactoryClass(type):
def __new__(factory, className ):
EntityClass = type.__new__(factory, className, (Entity,), {})
EntityClass.className = className
EntityClass.__init__ = initEntity
EntityClass.__init__ = Entity.initEntity
EntityClass.commandCreated = False
return EntityClass
......@@ -56,16 +37,20 @@ def PyEntityFactory( className, context ):
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).
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):
for e in filter(lambda x: not x in Entity.entityClassNameList, cxx_entityList):
# Store new class in dictionary with class name
PyEntityFactory( e,dictionary )
# Store class name in local list
entityClassNameList.append(e)
Entity.entityClassNameList.append(e)
# --- ENTITY -------------------------------------------------------------------
# --- ENTITY -------------------------------------------------------------------
# --- ENTITY -------------------------------------------------------------------
class Entity (object) :
"""
......@@ -81,6 +66,18 @@ class Entity (object) :
"""
object.__setattr__(self, 'obj', wrap.create_entity(className, instanceName) )
@staticmethod
def initEntity(self, name):
"""
Common constructor of specialized Entity classes. This function is bound
by the factory to each new class derivated from the Entity class as the
constructor of the new class.
"""
Entity.__init__(self, self.className, name)
if not self.__class__.commandCreated:
self.boundClassCommands()
self.__class__.commandCreated = True
@property
def name(self) :
return wrap.entity_get_name(self.obj)
......@@ -148,6 +145,39 @@ class Entity (object) :
except:
object.__getattr__(self, name)
def __setattr__(self, name, value):
if name in map(lambda s: s.getName().split(':')[-1],self.signals()):
raise NameError(name+" already designates a signal. "
"It is not advised to set a new attribute of the same name.")
object.__setattr__(self, name, value)
# --- COMMANDS BINDER -----------------------------------------------------
# List of all the entity classes from the c++ factory, that have been bound
# bind the py factory.
entityClassNameList = []
# This function dynamically create the function object that runs the command.
@staticmethod
def createCommandBind(name, docstring) :
def commandBind(self, *arg):
return wrap.entity_execute_command(self.obj, name, arg)
commandBind.__doc__ = docstring
return commandBind
def boundClassCommands(self):
"""
This static function has to be called from a class heritating from Entity.
It should be called only once. It parses the list of commands obtained from
c++, and bind each of them to a python class method.
"""
# 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 cmdstr in commands:
docstr = wrap.entity_get_command_docstring(self.obj, cmdstr)
cmdpy = Entity.createCommandBind(cmdstr, docstr)
setattrpath(self.__class__, cmdstr, cmdpy)
def boundNewCommand(self,cmdName):
"""
At construction, all existing commands are bound directly in the class.
......@@ -157,7 +187,8 @@ class Entity (object) :
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)
cmd = Entity.createCommandBind(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):
......@@ -170,9 +201,3 @@ class Entity (object) :
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()
......@@ -77,9 +77,20 @@ class SignalDepPrint:
setattr(SignalBase,'deps',property(SignalDepPrint))
setattr(Entity,'sigs',property(Entity.displaySignals))
setattr(Entity,'__repr__',Entity.__str__)
# Changing prompt
import sys
sys.ps1 = '% '
# Enable function that can be call without()def optionalparentheses(f):
def optionalparentheses(f):
class decoclass:
def __repr__(self):
res=f()
if isinstance(res,str): return res
else: return ''
def __call__(self,*arg):
return f(*arg)
return decoclass()
......@@ -23,7 +23,7 @@ def stringToTuple (vector) :
# check size
if len(vector) != size:
raise TypeError('displayed size ' +
size + ' of vector does not fit actual size: '
str(size) + ' of vector does not fit actual size: '
+ str(len(vector)))
res = map(float, vector)
return tuple (res)
......@@ -238,14 +238,4 @@ class SignalBase (object) :
"""
return(wrap.signal_base_display_dependencies(self.obj,iter))
# Script short-cuts: don't use this syntaxt in python coding,
# use it for debuging online only!
@property
def m(self):
"""
m stands for matlab: display the content of the
signal with matlab style, for debuging and transfert.
matlab-style to be coded ...
"""
print(self.value)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment