diff --git a/.pkglts/pkg_cfg.json b/.pkglts/pkg_cfg.json index 07bc35cc..e7cbdcee 100644 --- a/.pkglts/pkg_cfg.json +++ b/.pkglts/pkg_cfg.json @@ -7,10 +7,6 @@ }, "base": { "authors": [ - [ - "openalea", - "openalea@inria.fr" - ], [ "Christophe Pradal", "christophe dot pradal at cirad dot fr" @@ -36,7 +32,7 @@ ] }, "github": { - "owner": "{{ base.authors[0][0] }}", + "owner": "openalea", "project": "{{ base.pkgname }}", "url": "https://github.com/{{ github.owner }}/{{ github.project }}" }, @@ -50,7 +46,7 @@ "intended_versions": [ "27" ], - "require": [["git", "openalea/deploy"]] + "require": [["git", "openalea/deploy"], ["git", "openalea/provenance"]] }, "readthedocs": { "project": "openalea-core" diff --git a/.pkglts/pkg_hash.json b/.pkglts/pkg_hash.json index be7a8594..2c5f3c21 100644 --- a/.pkglts/pkg_hash.json +++ b/.pkglts/pkg_hash.json @@ -9,11 +9,11 @@ "travis": "p39laCS5PHN7gbwAtgU28Z+UXHRifGIORlali3ZkK7OQKjjRhn1Dbwscp76SZeocjKUEBtl3fI1857Ri37wPWQ==", "travis.addons": "z4PhNX7vuL3xVChQ1m2AB9Yg5AULVxXcg/SpIdNs6c5H0NE8XYXysP+DGNKHfuwvY7kxvUdBeoGlODJ6+SfaPg==", "travis.after": "z4PhNX7vuL3xVChQ1m2AB9Yg5AULVxXcg/SpIdNs6c5H0NE8XYXysP+DGNKHfuwvY7kxvUdBeoGlODJ6+SfaPg==", - "travis.install": "CwigKKORJdg9WEl3DxAU095HFtme5Hwv7S2mH5Lgo0sUuwWuoSyhs+pBYWCzDXGyxZIcTPSIEY5/0PuaYqGR6Q==", + "travis.install": "Ay/BrD6JoeZi+JszHb0sHpFfzVEp9qaeFsWBBBJG0t2xwgF3tinQxifkNFwuJdlyCjy6U9k901dZnqt6yrzzxQ==", "travis.script": "STjpu3u3YoOeTz4mBIflZ58OodPdFRPFtLt6c8CUciNwe/fYhCTxlKTMB/S7VL1ippUsQVIfrFGl+OQ/ALWmPQ==" }, "AUTHORS.rst": { - "doc": "mr4dDvb808KCdcLSRWe9brxcIBamJp3DMpFzoEhHCeSLmr7Q0QfrNRZ79dnneEyWHgcs2srtibLIZlGOq1S0rQ==" + "doc": "HvXVe1vS1t/xzXuerP756vvyf3I4V8xEOqvNIEGejKpuzVRZr6wR4C24rm8O9OnBsYedYHvDxQRF25urtQCDMQ==" }, "CONTRIBUTING.rst": {}, "HISTORY.rst": {}, @@ -32,7 +32,7 @@ "doc/_static/nonempty.txt": {}, "doc/authors.rst": {}, "doc/conf.py": { - "sphinx": "tTFNmgl+NIWu4UMwBw2aJyhQQDpiLrp/aYkMscpqFQWjeHO7YBU9ErwQX5XnRLMGZHCtBsweFcnlbzN2b0NsBg==" + "sphinx": "vfmn2Bw5s7XSpWirr5eXEjxifmpqNg4YCiNCojKEmRaCHDw3F/yzd6ghqanWEdjEkbs7Dn9Z9U3jdHBM6/j3oA==" }, "doc/contributing.rst": {}, "doc/history.rst": {}, @@ -47,14 +47,14 @@ "pysetup": "XWPKeIfT2RoNPeDhPDgWWOssKAjkq/OXoEfIpSs8vJrYkPahRrEs1qXFvqxzqoV09MjmnVg0zrG9m/wRXfrRxw==" }, "requirements.txt": { - "pysetup": "/5djJXLbrvuFk7LIgtfgYR8RnQrY5BEmOB4zEd0PrKeswR/8sQkzj4yKy7Zl3LAdRzYjPDhWiRkS1oMCG4FX7Q==" + "pysetup": "ROpjsUQMjMbn87UPzWB8XD7JnQAUNptjTBj99UwCmDUKNGQNqmlZD0gN+ukVdk4E87brwVEgqOZ47nid1EGpww==" }, "setup.cfg": { "pysetup": "QBedkKDNLW8WmznOFdyIyCL2sTDHYcmudSzjx+7QUcRI1vVxIHnNm82aiMvaMeEAYpOCr+8+Nj4ZTr9P0dSxSg==" }, "setup.py": { "pysetup.call": "2wHuP94SpWKZpqOzExkQGTxnhGPgBHK3qOdPn0Ncstj5FkZ7FBGGM/inqAXaI4QLKQtTNlOUYRGSkYUWAUcf1w==", - "pysetup.kwds": "2Wo8eNut4J6R97mY1RTBwstqt7yVHd/9KVgNH17IV7oOc5Wb1g8Vcpgm7H9sabVWjkN9V7QQYNNZEneBkTNddw==" + "pysetup.kwds": "dlgrvck1HbacSgA60B/51tvoA65q1tPJ/9ZWW0mrNh0uCq4ceY5GW2McnmDVal/PjP19xCfhoyUBuElz9HvuSA==" }, "src/openalea/core/__init__.py": { "base": "gR33dW0qqYmsV9NSNB+DD8XmuxnC2t0mKjnMoU5728qh97fSER6MbX+3QKxpZDLByZToaAay4xhx8acxketJmA==" diff --git a/.travis.yml b/.travis.yml index e5ce3cc2..ef39fc18 100644 --- a/.travis.yml +++ b/.travis.yml @@ -37,6 +37,7 @@ install: - pip install git+https://github.com/openalea/deploy + - pip install git+https://github.com/openalea/provenance - conda install coverage - conda install mock - conda install nose diff --git a/AUTHORS.rst b/AUTHORS.rst index 598449c8..e8409b7c 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -8,7 +8,6 @@ Development Lead .. {# pkglts, doc -* openalea, * Christophe Pradal, * Samuel Dufour-Kowalski, * revesansparole, diff --git a/doc/conf.py b/doc/conf.py index 2f4b2211..13cac438 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -247,7 +247,7 @@ latex_documents = [ ('index', 'core.tex', u'core Documentation', - u'openalea', 'manual'), + u'Christophe Pradal', 'manual'), ] # The name of an image file (relative to this directory) to place at @@ -278,7 +278,7 @@ man_pages = [ ('index', 'core', u'core Documentation', - [u'openalea'], 1) + [u'Christophe Pradal'], 1) ] # If true, show URL addresses after external links. @@ -293,7 +293,7 @@ texinfo_documents = [ ('index', 'core', u'core Documentation', - u'openalea', + u'Christophe Pradal', 'core', 'OpenAlea.Core is able to discover and manage packages and logical components, build and evaluate dataflows and Generate final applications', 'Miscellaneous'), diff --git a/requirements.txt b/requirements.txt index 6c4c1dd4..7657a191 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,6 +3,8 @@ # edit .pkglts/pkg_cfg instead # section pysetup +# openalea/deploy +# openalea/provenance # #} diff --git a/setup.py b/setup.py index 5261e790..2197bafc 100644 --- a/setup.py +++ b/setup.py @@ -23,8 +23,8 @@ version=version["__version__"], description=short_descr, long_description=readme + '\n\n' + history, - author="openalea, Christophe Pradal, Samuel Dufour-Kowalski, revesansparole, ", - author_email="openalea@inria.fr, christophe dot pradal at cirad dot fr, dufourko at cirad dot fr, revesansparole@gmail.com, ", + author="Christophe Pradal, Samuel Dufour-Kowalski, revesansparole, ", + author_email="christophe dot pradal at cirad dot fr, dufourko at cirad dot fr, revesansparole@gmail.com, ", url='https://github.com/openalea/core', license='cecill-c', zip_safe=False, diff --git a/src/openalea/core/algo/dataflow_evaluation.py b/src/openalea/core/algo/dataflow_evaluation.py index f3cf618b..4e2170c6 100644 --- a/src/openalea/core/algo/dataflow_evaluation.py +++ b/src/openalea/core/algo/dataflow_evaluation.py @@ -22,124 +22,133 @@ import sys from time import clock import traceback as tb -from openalea.core import ScriptLibrary +from openalea.provenance.simple_dict import Provenance as RVProvenance +from openalea.core import ScriptLibrary from openalea.core.dataflow import SubDataflow from openalea.core.interface import IFunction - -PROVENANCE = False - -# Implement provenance in OpenAlea -db_conn = None - -import sqlite3 -from openalea.core.path import path -from openalea.core import settings - -def db_create(cursor): - cur = cursor - #-prospective provenance-# - #User table creation - cur.execute("CREATE TABLE IF NOT EXISTS User (userid INTEGER,createtime DATETIME,name varchar (25), firstname varchar (25), email varchar (25), password varchar (25),PRIMARY KEY(userid))") - - # CompositeNode table creation - cur.execute("CREATE TABLE IF NOT EXISTS CompositeNode (CompositeNodeid INTEGER, creatime DATETIME, name varchar (25), description varchar (25),userid INTEGER,PRIMARY KEY(CompositeNodeid),FOREIGN KEY(userid) references User)") - #Cr?ation de la table Node - cur.execute("CREATE TABLE IF NOT EXISTS Node (Nodeid INTEGER, createtime DATETIME, name varchar (25), NodeFactory varchar (25),CompositeNodeid INTEGER,PRIMARY KEY(Nodeid),FOREIGN KEY(CompositeNodeid) references CompsiteNode)") - #Cr?ation de la table Input - cur.execute("CREATE TABLE IF NOT EXISTS Input (Inputid INTEGER, createtime DATETIME, name varchar (25), typedata varchar (25), InputPort INTEGER,PRIMARY KEY (Inputid))") - #Cr?ation de la table Output - cur.execute("CREATE TABLE IF NOT EXISTS Output (Outputid INTEGER, createtime DATETIME, name varchar (25), typedata varchar (25), OutputPort INTEGER,PRIMARY KEY (Outputid))") - #Cr?ation de la table elt_connection - cur.execute("CREATE TABLE IF NOT EXISTS elt_connection (elt_connectionid INTEGER, createtime DATETIME,srcNodeid INTEGER, srcNodeOutputPortid INTEGER, targetNodeid INTEGER, targetNodeInputPortid INTEGER ,PRIMARY KEY (elt_connectionid))") - - #- retrospective provenance -# - #- CompositeNodeExec table creation - cur.execute("CREATE TABLE IF NOT EXISTS CompositeNodeExec (CompositeNodeExecid INTEGER, createtime DATETIME, endtime DATETIME,userid INTEGER,CompositeNodeid INTEGER,PRIMARY KEY(CompositeNodeExecid),FOREIGN KEY(CompositeNodeid) references CompositeNode,FOREIGN KEY(userid) references User)") - #- NodeExec - cur.execute("CREATE TABLE IF NOT EXISTS NodeExec (NodeExecid INTEGER, createtime DATETIME, endtime DATETIME,Nodeid INTEGER,CompositeNodeExecid INTEGER,dataid INTEGER,PRIMARY KEY(NodeExecid),FOREIGN KEY(Nodeid) references Node, FOREIGN KEY (CompositeNodeExecid) references CompositeNodeExec, FOREIGN KEY (dataid) references Data)") - #- History - cur.execute("CREATE TABLE IF NOT EXISTS Histoire (Histoireid INTEGER, createtime DATETIME, name varchar (25), description varchar (25),userid INTEGER,CompositeNodeExecid INTEGER,PRIMARY KEY (Histoireid), FOREIGN KEY(Userid) references User, FOREIGN KEY(CompositeNodeExecid) references CompositeNodeExec)") - #- Data - cur.execute("CREATE TABLE IF NOT EXISTS Data (dataid INTEGER, createtime DATETIME,NodeExecid INTEGER, PRIMARY KEY(dataid),FOREIGN KEY(NodeExecid) references NodeExec)") - #- Tag - cur.execute("CREATE TABLE IF NOT EXISTS Tag (CompositeNodeExecid INTEGER, createtime DATETIME, name varchar(25),userid INTEGER,PRIMARY KEY(CompositeNodeExecid),FOREIGN KEY(userid) references User)") - return cur - -def get_database_name(): - db_fn = path(settings.get_openalea_home_dir())/'provenance.sq3' - return db_fn - -def db_connexion(): - """ Return a curso on the database. - - If the database does not exists, create it. - """ - global db_conn - if db_conn is None: - db_fn = get_database_name() - if not db_fn.exists(): - db_conn=sqlite3.connect(db_fn) - cur = db_conn.cursor() - cur = db_create(cur) - return cur - else: - cur = db_conn.cursor() - return cur - -class Provenance(object): - def __init__(self, workflow): - self.clear() - self.workflow = workflow - - def edges(self): - cn = self.workflow - edges= list(cn.edges()) - sources=map(cn.source,edges) - targets = map(cn.target,edges) - source_ports=[cn.local_id(cn.source_port(eid)) for eid in edges] - target_ports=[cn.local_id(cn.target_port(eid)) for eid in edges] - _edges = dict(zip(edges,zip(sources,source_ports,targets, target_ports))) - return _edges - - def clear(self): - self.nodes = [] - - def start_time(self): - pass - def end_time(self): - pass - def workflow_exec(self, *args): - pass - def node_exec(self, vid, node, start_time, end_time, *args): - pass - def write(self): - """ Write the provenance in db """ - -class PrintProvenance(Provenance): - def workflow_exec(self, *args): - print 'Workflow execution ', self.workflow.factory.name - def node_exec(self, vid, node, start_time, end_time, *args): - provenance(vid, node, start_time, end_time) +# PROVENANCE = False -def provenance(vid, node, start_time, end_time): - #from service import db - #conn = db.connect() - +# # Implement provenance in OpenAlea +# db_conn = None +# +# import sqlite3 +# from openalea.core.path import path +# from openalea.core import settings +# +# def db_create(cursor): +# cur = cursor +# #-prospective provenance-# +# #User table creation +# cur.execute("CREATE TABLE IF NOT EXISTS User (userid INTEGER,createtime DATETIME,name varchar (25), firstname varchar (25), email varchar (25), password varchar (25),PRIMARY KEY(userid))") +# +# # CompositeNode table creation +# cur.execute("CREATE TABLE IF NOT EXISTS CompositeNode (CompositeNodeid INTEGER, creatime DATETIME, name varchar (25), description varchar (25),userid INTEGER,PRIMARY KEY(CompositeNodeid),FOREIGN KEY(userid) references User)") +# #Cr?ation de la table Node +# cur.execute("CREATE TABLE IF NOT EXISTS Node (Nodeid INTEGER, createtime DATETIME, name varchar (25), NodeFactory varchar (25),CompositeNodeid INTEGER,PRIMARY KEY(Nodeid),FOREIGN KEY(CompositeNodeid) references CompsiteNode)") +# #Cr?ation de la table Input +# cur.execute("CREATE TABLE IF NOT EXISTS Input (Inputid INTEGER, createtime DATETIME, name varchar (25), typedata varchar (25), InputPort INTEGER,PRIMARY KEY (Inputid))") +# #Cr?ation de la table Output +# cur.execute("CREATE TABLE IF NOT EXISTS Output (Outputid INTEGER, createtime DATETIME, name varchar (25), typedata varchar (25), OutputPort INTEGER,PRIMARY KEY (Outputid))") +# #Cr?ation de la table elt_connection +# cur.execute("CREATE TABLE IF NOT EXISTS elt_connection (elt_connectionid INTEGER, createtime DATETIME,srcNodeid INTEGER, srcNodeOutputPortid INTEGER, targetNodeid INTEGER, targetNodeInputPortid INTEGER ,PRIMARY KEY (elt_connectionid))") +# +# #- retrospective provenance -# +# #- CompositeNodeExec table creation +# cur.execute("CREATE TABLE IF NOT EXISTS CompositeNodeExec (CompositeNodeExecid INTEGER, createtime DATETIME, endtime DATETIME,userid INTEGER,CompositeNodeid INTEGER,PRIMARY KEY(CompositeNodeExecid),FOREIGN KEY(CompositeNodeid) references CompositeNode,FOREIGN KEY(userid) references User)") +# #- NodeExec +# cur.execute("CREATE TABLE IF NOT EXISTS NodeExec (NodeExecid INTEGER, createtime DATETIME, endtime DATETIME,Nodeid INTEGER,CompositeNodeExecid INTEGER,dataid INTEGER,PRIMARY KEY(NodeExecid),FOREIGN KEY(Nodeid) references Node, FOREIGN KEY (CompositeNodeExecid) references CompositeNodeExec, FOREIGN KEY (dataid) references Data)") +# #- History +# cur.execute("CREATE TABLE IF NOT EXISTS Histoire (Histoireid INTEGER, createtime DATETIME, name varchar (25), description varchar (25),userid INTEGER,CompositeNodeExecid INTEGER,PRIMARY KEY (Histoireid), FOREIGN KEY(Userid) references User, FOREIGN KEY(CompositeNodeExecid) references CompositeNodeExec)") +# #- Data +# cur.execute("CREATE TABLE IF NOT EXISTS Data (dataid INTEGER, createtime DATETIME,NodeExecid INTEGER, PRIMARY KEY(dataid),FOREIGN KEY(NodeExecid) references NodeExec)") +# #- Tag +# cur.execute("CREATE TABLE IF NOT EXISTS Tag (CompositeNodeExecid INTEGER, createtime DATETIME, name varchar(25),userid INTEGER,PRIMARY KEY(CompositeNodeExecid),FOREIGN KEY(userid) references User)") +# return cur +# +# def get_database_name(): +# db_fn = path(settings.get_openalea_home_dir())/'provenance.sq3' +# return db_fn +# +# def db_connexion(): +# """ Return a curso on the database. +# +# If the database does not exists, create it. +# """ +# global db_conn +# if db_conn is None: +# db_fn = get_database_name() +# if not db_fn.exists(): +# db_conn=sqlite3.connect(db_fn) +# cur = db_conn.cursor() +# cur = db_create(cur) +# return cur +# else: +# cur = db_conn.cursor() +# return cur + +# class Provenance(object): +# def __init__(self, workflow): +# self.clear() +# self.workflow = workflow +# +# def edges(self): +# cn = self.workflow +# edges = list(cn.edges()) +# sources = map(cn.source, edges) +# targets = map(cn.target, edges) +# source_ports = [cn.local_id(cn.source_port(eid)) for eid in edges] +# target_ports = [cn.local_id(cn.target_port(eid)) for eid in edges] +# _edges = dict( +# zip(edges, zip(sources, source_ports, targets, target_ports))) +# return _edges +# +# def clear(self): +# self.nodes = [] +# +# def start_time(self): +# pass +# +# def end_time(self): +# pass +# +# def workflow_exec(self, *args): +# pass +# +# def node_exec(self, vid, node, start_time, end_time, *args): +# pass +# +# def write(self): +# """ Write the provenance in db """ - if PROVENANCE: - cur = db_connexion() - pname = node.factory.package.name - name = node.factory.name +# class PrintProvenance(Provenance): +# def workflow_exec(self, *args): +# print 'Workflow execution ', self.workflow.factory.name +# +# def node_exec(self, vid, node, start_time, end_time, *args): +# provenance(vid, node, start_time, end_time) +# +# +# def provenance(vid, node, start_time, end_time): +# # from service import db +# # conn = db.connect() +# +# +# if PROVENANCE: +# cur = db_connexion() +# +# pname = node.factory.package.name +# name = node.factory.name +# +# print "Provenance Process:" +# print "instance ID ", vid, "Package Name: ", pname, "Name: ", name +# print "start time :", start_time, "end_time: ", end_time, "duration : ", end_time - start_time +# print 'Inputs : ', node.inputs +# print 'outputs : ', node.outputs - print "Provenance Process:" - print "instance ID ", vid, "Package Name: ",pname, "Name: ", name - print "start time :", start_time, "end_time: ", end_time, "duration : ", end_time-start_time - print 'Inputs : ', node.inputs - print 'outputs : ', node.outputs # print the evaluation time # This variable has to be retrieve by the settings @@ -147,8 +156,8 @@ def provenance(vid, node, start_time, end_time): __evaluators__ = [] -class EvaluationException(Exception): +class EvaluationException(Exception): def __init__(self, vid, node, exception, exc_info): Exception.__init__(self) self.vid = vid @@ -180,8 +189,8 @@ def cmp_posx(x, y): """todo""" (xpid, xvid, xactor) = x (ypid, yvid, yactor) = y - #px = xactor.internal_data.get('posx', 0) - #py = yactor.internal_data.get('posx', 0) + # px = xactor.internal_data.get('posx', 0) + # py = yactor.internal_data.get('posx', 0) px = xactor.get_ad_hoc_dict().get_metadata('position')[0] py = yactor.get_ad_hoc_dict().get_metadata('position')[0] @@ -196,15 +205,20 @@ def cmp_posx(x, y): """ Abstract evaluation algorithm """ -class AbstractEvaluation(object): - def __init__(self, dataflow): +class AbstractEvaluation(object): + def __init__(self, dataflow, record_provenance=False): """ :param dataflow: to be done """ self._dataflow = dataflow - if PROVENANCE: - self.provenance = PrintProvenance(dataflow) + # if PROVENANCE: + # self.provenance = PrintProvenance(dataflow) + + if record_provenance: + self._prov = RVProvenance() + else: + self._prov = None def eval(self, *args): """todo""" @@ -223,14 +237,25 @@ def eval_vertex_code(self, vid): node = self._dataflow.actor(vid) try: + # prov before + # print "prov", node.get_caption() + + if self._prov is not None: + self._prov.before_eval(self._dataflow, vid) + t0 = clock() ret = node.eval() t1 = clock() + # prov before + # print "prov", node.get_caption() + + if self._prov is not None: + self._prov.after_eval(self._dataflow, vid) + + # if PROVENANCE: + # self.provenance.node_exec(vid, node, t0, t1) + # # provenance(vid, node, t0,t1) - if PROVENANCE: - self.provenance.node_exec(vid, node, t0,t1) - #provenance(vid, node, t0,t1) - # When an exception is raised, a flag is set. # So we remove it when evaluation is ok. node.raise_exception = False @@ -252,8 +277,7 @@ def eval_vertex_code(self, vid): node.raise_exception = True node.notify_listeners(('data_modified', None, None)) raise EvaluationException(vid, node, e, \ - tb.format_tb(sys.exc_info()[2])) - + tb.format_tb(sys.exc_info()[2])) def get_parent_nodes(self, pid): """ @@ -266,7 +290,7 @@ def get_parent_nodes(self, pid): # For each connected node npids = [(npid, df.vertex(npid), df.actor(df.vertex(npid))) \ - for npid in df.connected_ports(pid)] + for npid in df.connected_ports(pid)] npids.sort(cmp=cmp_posx) return npids @@ -274,13 +298,14 @@ def get_parent_nodes(self, pid): def set_provenance(self, provenance): self.provenance = provenance + class BrutEvaluation(AbstractEvaluation): """ Basic evaluation algorithm """ __evaluators__.append("BrutEvaluation") - def __init__(self, dataflow): + def __init__(self, dataflow, record_provenance=False): - AbstractEvaluation.__init__(self, dataflow) + AbstractEvaluation.__init__(self, dataflow, record_provenance) # a property to specify if the node has already been evaluated self._evaluated = set() @@ -294,7 +319,8 @@ def is_stopped(self, vid, actor): if actor.block: status = True n = actor.get_nb_output() - outputs = [i for i in range(n) if actor.get_output(i) is not None ] + outputs = [i for i in range(n) if + actor.get_output(i) is not None] if not outputs: status = False return status @@ -341,12 +367,12 @@ def eval(self, *args): self._evaluated.clear() # Eval from the leaf - for vid in (vid for vid in df.vertices() if df.nb_out_edges(vid)==0): + for vid in (vid for vid in df.vertices() if df.nb_out_edges(vid) == 0): self.eval_vertex(vid) t1 = clock() if quantify: - print "Evaluation time: %s"%(t1-t0) + print "Evaluation time: %s" % (t1 - t0) class PriorityEvaluation(BrutEvaluation): @@ -357,7 +383,8 @@ def eval(self, vtx_id=None, *args, **kwds): """todo""" t0 = clock() - is_subdataflow = False if not kwds else kwds.get('is_subdataflow', False) + is_subdataflow = False if not kwds else kwds.get('is_subdataflow', + False) df = self._dataflow # Unvalidate all the nodes if is_subdataflow: @@ -370,7 +397,7 @@ def eval(self, vtx_id=None, *args, **kwds): # Select the leaves (list of (vid, actor)) leaves = [(vid, df.actor(vid)) - for vid in df.vertices() if df.nb_out_edges(vid)==0] + for vid in df.vertices() if df.nb_out_edges(vid) == 0] leaves.sort(cmp_priority) @@ -380,19 +407,19 @@ def eval(self, vtx_id=None, *args, **kwds): t1 = clock() if quantify: - print "Evaluation time: %s"%(t1-t0) + print "Evaluation time: %s" % (t1 - t0) class GeneratorEvaluation(AbstractEvaluation): """ Evaluation algorithm with generator / priority and selection""" __evaluators__.append("GeneratorEvaluation") - def __init__(self, dataflow): + def __init__(self, dataflow, record_provenance=False): - AbstractEvaluation.__init__(self, dataflow) + AbstractEvaluation.__init__(self, dataflow, record_provenance) # a property to specify if the node has already been evaluated self._evaluated = set() - self.reeval = False # Flag to force reevaluation (for generator) + self.reeval = False # Flag to force reevaluation (for generator) def is_stopped(self, vid, actor): """ Return True if evaluation must be stop at this vertex """ @@ -454,7 +481,7 @@ def eval(self, vtx_id=None, step=False): else: # Select the leafs (list of (vid, actor)) leafs = [(vid, df.actor(vid)) - for vid in df.vertices() if df.nb_out_edges(vid)==0] + for vid in df.vertices() if df.nb_out_edges(vid) == 0] leafs.sort(cmp_priority) @@ -462,25 +489,24 @@ def eval(self, vtx_id=None, step=False): for vid, actor in leafs: if not self.is_stopped(vid, actor): self.reeval = True - while(self.reeval): + while (self.reeval): self.clear() self.eval_vertex(vid) t1 = clock() if quantify: - print "Evaluation time: %s"%(t1-t0) + print "Evaluation time: %s" % (t1 - t0) return False - class LambdaEvaluation(PriorityEvaluation): """ Evaluation algorithm with support of lambda / priority and selection""" __evaluators__.append("LambdaEvaluation") - def __init__(self, dataflow): - PriorityEvaluation.__init__(self, dataflow) + def __init__(self, dataflow, record_provenance=False): + PriorityEvaluation.__init__(self, dataflow, record_provenance) - self.lambda_value = {} # lambda resolution dictionary + self.lambda_value = {} # lambda resolution dictionary self._resolution_node = set() def eval_vertex(self, vid, context, lambda_value, *args): @@ -528,7 +554,7 @@ def eval_vertex(self, vid, context, lambda_value, *args): transmit_cxt = context transmit_lambda = lambda_value - cpt = 0 # parent counter + cpt = 0 # parent counter # For each connected node for npid, nvid, nactor in self.get_parent_nodes(pid): @@ -548,7 +574,7 @@ def eval_vertex(self, vid, context, lambda_value, *args): # replace the lambda with value. if (isinstance(outval, SubDataflow) - and interface is not IFunction): + and interface is not IFunction): if (not context and not lambda_value): # we are not in resolution mode @@ -566,7 +592,8 @@ def eval_vertex(self, vid, context, lambda_value, *args): try: lambda_value[outval] = context.pop() except Exception: - raise Exception("The number of lambda variables is insuffisant") + raise Exception( + "The number of lambda variables is insuffisant") # We replace the value with a context value outval = lambda_value[outval] @@ -597,9 +624,13 @@ def eval(self, vtx_id=None, context=None, is_subdataflow=False, step=False): :param context: list a value to assign to lambda variables """ t0 = clock() - if PROVENANCE and (not is_subdataflow): - self.provenance.workflow_exec() - self.provenance.start_time() + if self._prov is not None: + self._prov.init(self._dataflow) + self._prov.time_init = t0 + + # if PROVENANCE and (not is_subdataflow): + # self.provenance.workflow_exec() + # self.provenance.start_time() self.lambda_value.clear() @@ -608,22 +639,28 @@ def eval(self, vtx_id=None, context=None, is_subdataflow=False, step=False): # thus, we have to reverse the arguments to evaluate the function (FIFO). context.reverse() - PriorityEvaluation.eval(self, vtx_id, context, self.lambda_value, is_subdataflow=is_subdataflow) - self.lambda_value.clear() # do not keep context in memory - - if PROVENANCE: - self.provenance.end_time() + PriorityEvaluation.eval(self, vtx_id, context, self.lambda_value, + is_subdataflow=is_subdataflow) + self.lambda_value.clear() # do not keep context in memory + + # if PROVENANCE: + # self.provenance.end_time() t1 = clock() + if self._prov is not None: + self._prov.time_end = t1 + if quantify: - print "Evaluation time: %s"%(t1-t0) + print "Evaluation time: %s" % (t1 - t0) if not is_subdataflow: self._resolution_node.clear() DefaultEvaluation = LambdaEvaluation -#DefaultEvaluation = GeneratorEvaluation + + +# DefaultEvaluation = GeneratorEvaluation # from collections import deque @@ -896,11 +933,12 @@ def eval(self, *args, **kwds): # Eval from the leaf script = "" - for vid in (vid for vid in df.vertices() if df.nb_out_edges(vid)==0): + for vid in (vid for vid in df.vertices() if df.nb_out_edges(vid) == 0): script += self.eval_vertex(vid) return script + ############################################################################ # Evaluation with scheduling @@ -915,7 +953,7 @@ def __init__(self, dataflow): AbstractEvaluation.__init__(self, dataflow) # a property to specify if the node has already been evaluated self._evaluated = set() - self.reeval = False # Flag to force reevaluation (for generator) + self.reeval = False # Flag to force reevaluation (for generator) # CPL # At each evaluation of the dataflow, increase the current cycle of @@ -932,7 +970,7 @@ def is_stopped(self, vid, actor): """ Return True if evaluation must be stop at this vertex """ stopped = False try: - if hasattr(actor,'block'): + if hasattr(actor, 'block'): stopped = actor.block stopped = stopped or vid in self._evaluated except: @@ -956,7 +994,7 @@ def next_step(self): def eval_vertex(self, vid): """ Evaluate the vertex vid """ - #print "Step ", self._current_cycle + # print "Step ", self._current_cycle df = self._dataflow actor = df.actor(vid) @@ -998,7 +1036,6 @@ def eval_vertex(self, vid): if delay == 0: delay = self.eval_vertex_code(vid) - # Reevaluation flag # TODO: Add the node to the scheduler rather to execute if (delay): @@ -1023,7 +1060,7 @@ def eval(self, vtx_id=None, step=False): else: # Select the leafs (list of (vid, actor)) leafs = [(vid, df.actor(vid)) - for vid in df.vertices() if df.nb_out_edges(vid)==0] + for vid in df.vertices() if df.nb_out_edges(vid) == 0] leafs.sort(cmp_priority) @@ -1032,7 +1069,7 @@ def eval(self, vtx_id=None, step=False): if not self.is_stopped(vid, actor): self.reeval = True if not step: - while(self.reeval and not self._stop): + while (self.reeval and not self._stop): self.clear() self.eval_vertex(vid) self.next_step() @@ -1046,7 +1083,7 @@ def eval(self, vtx_id=None, step=False): for vid in self._nodes_to_reset: df.actor(vid).reset() - #print 'Run %d times the dataflow'%(self._current_cycle,) + # print 'Run %d times the dataflow'%(self._current_cycle,) # Reset the state if not step: @@ -1055,7 +1092,7 @@ def eval(self, vtx_id=None, step=False): t1 = clock() if quantify: - print "Evaluation time: %s"%(t1-t0) + print "Evaluation time: %s" % (t1 - t0) return False @@ -1083,17 +1120,16 @@ def is_operator(actor): if 'SciFloware' not in factory.package.name: return False elif factory.name in algebra: - return True + return True else: return False - + def scifloware_actors(self): """ Compute the scifloware actors. Only those actors will be evaluated. """ - df = self._dataflow self._scifloware_actors.clear() for vid in df.vertices(): @@ -1101,7 +1137,6 @@ def scifloware_actors(self): if self.is_operator(actor): self._scifloware_actors.add(vid) - def eval_vertex(self, vid): """ Evaluate the vertex vid @@ -1117,7 +1152,7 @@ def eval_vertex(self, vid): """ - #print "Step ", self._current_cycle + # print "Step ", self._current_cycle df = self._dataflow actor = df.actor(vid) @@ -1125,7 +1160,7 @@ def eval_vertex(self, vid): is_op = vid in self._scifloware_actors self._evaluated.add(vid) - #assert self.is_operator(actor) + # assert self.is_operator(actor) # For each inputs # Compute the nodes @@ -1142,17 +1177,18 @@ def eval_vertex(self, vid): out_ports = list(df.connected_ports(pid)) nb_out = len(out_ports) if nb_out > 1: - raise Exception('Too many nodes connected to the SciFloware operator.') + raise Exception( + 'Too many nodes connected to the SciFloware operator.') elif nb_out == 1: out_actor = df.actor(df.vertex(out_ports[0])) - dataflow_name = out_actor.factory.package.name+':'+out_actor.factory.name + dataflow_name = out_actor.factory.package.name + ':' + out_actor.factory.name actor.set_input(df.local_id(pid), dataflow_name) else: cpt = 0 # For each connected node for npid, nvid, nactor in self.get_parent_nodes(pid): # Do no reevaluate the same node - + if not self.is_stopped(nvid, nactor): self.eval_vertex(nvid) @@ -1168,7 +1204,6 @@ def eval_vertex(self, vid): self.eval_vertex_code(vid) - def eval(self, vtx_id=None, **kwds): t0 = clock() @@ -1180,7 +1215,7 @@ def eval(self, vtx_id=None, **kwds): else: # Select the leafs (list of (vid, actor)) leafs = [(vid, df.actor(vid)) - for vid in df.vertices() if df.nb_out_edges(vid)==0] + for vid in df.vertices() if df.nb_out_edges(vid) == 0] leafs.sort(cmp_priority) @@ -1190,6 +1225,6 @@ def eval(self, vtx_id=None, **kwds): t1 = clock() if quantify: - print "Evaluation time: %s"%(t1-t0) + print "Evaluation time: %s" % (t1 - t0) return False diff --git a/src/openalea/core/compositenode.py b/src/openalea/core/compositenode.py index 0cd7109f..5f02e40d 100644 --- a/src/openalea/core/compositenode.py +++ b/src/openalea/core/compositenode.py @@ -38,13 +38,13 @@ quantify = False + class IncompatibleNodeError(Exception): """todo""" pass class CompositeNodeFactory(AbstractFactory): - mimetype = "openalea/compositenodefactory" """ @@ -120,7 +120,7 @@ def copy(self, **args): for k, v in ret.elt_factory.iteritems(): pkg_id, factory_id = v - if(pkg_id == old_pkg.get_id()): + if (pkg_id == old_pkg.get_id()): pkg_id = new_pkg.get_id() ret.elt_factory[k] = pkg_id, factory_id @@ -153,7 +153,7 @@ def instantiate(self, call_stack=None): new_df.set_caption(self.get_id()) new_df.eval_algo = self.eval_algo - cont_eval = set() # continuous evaluated nodes + cont_eval = set() # continuous evaluated nodes # Instantiate the node with each factory for vid in self.elt_factory: @@ -161,7 +161,7 @@ def instantiate(self, call_stack=None): node = self.instantiate_node(vid, call_stack) # Manage continuous eval - if(node.user_application): + if (node.user_application): cont_eval.add(vid) except (UnknownNodeError, UnknownPackageError): @@ -171,7 +171,7 @@ def instantiate(self, call_stack=None): print "-> Cannot find '%s:%s'" % (pkg, fact) node = self.create_fake_node(vid) node.raise_exception = True - node.notify_listeners(('data_modified', None, None )) + node.notify_listeners(('data_modified', None, None)) new_df.add_node(node, vid, False) @@ -179,10 +179,12 @@ def instantiate(self, call_stack=None): try: self.load_ad_hoc_data(new_df.node(new_df.id_in), copy.deepcopy(self.elt_data["__in__"]), - copy.deepcopy(self.elt_ad_hoc.get("__in__", None))) + copy.deepcopy( + self.elt_ad_hoc.get("__in__", None))) self.load_ad_hoc_data(new_df.node(new_df.id_out), copy.deepcopy(self.elt_data["__out__"]), - copy.deepcopy(self.elt_ad_hoc.get("__out__", None))) + copy.deepcopy( + self.elt_ad_hoc.get("__out__", None))) except: pass @@ -191,23 +193,23 @@ def instantiate(self, call_stack=None): (source_vid, source_port, target_vid, target_port) = link # Replace id for in and out nodes - if(source_vid == '__in__'): + if (source_vid == '__in__'): source_vid = new_df.id_in - if(target_vid == '__out__'): + if (target_vid == '__out__'): target_vid = new_df.id_out new_df.connect(source_vid, source_port, target_vid, target_port) # Set continuous evaluation for vid in cont_eval: - new_df.set_continuous_eval(vid, True) + new_df.set_continuous_eval(vid, True) # Set call stack to its original state call_stack.pop() # Properties new_df.lazy = self.lazy - new_df.graph_modified = False # Graph is not modifyied + new_df.graph_modified = False # Graph is not modifyied return new_df @@ -222,41 +224,40 @@ def create_fake_node(self, vid): for eid, link in self.connections.iteritems(): (source_vid, source_port, target_vid, target_port) = link - if(source_vid == vid): + if (source_vid == vid): outs = max(outs, source_port) - elif(target_vid == vid): + elif (target_vid == vid): ins = max(ins, target_port) node = Node() attributes = copy.deepcopy(self.elt_data[vid]) - ad_hoc = copy.deepcopy(self.elt_ad_hoc.get(vid, None)) + ad_hoc = copy.deepcopy(self.elt_ad_hoc.get(vid, None)) self.load_ad_hoc_data(node, attributes, ad_hoc) # copy node input data if any values = copy.deepcopy(self.elt_value.get(vid, ())) - for p in range(ins+1): - port = node.add_input(name="In"+str(p)) + for p in range(ins + 1): + port = node.add_input(name="In" + str(p)) - for p in range(outs+1): - port = node.add_output(name="Out"+str(p)) + for p in range(outs + 1): + port = node.add_output(name="Out" + str(p)) for vs in values: try: - #the two first elements are the historical - #values : port Id and port value - #beyond that are extensions added by gengraph: - #the ad_hoc_dict representation is third. + # the two first elements are the historical + # values : port Id and port value + # beyond that are extensions added by gengraph: + # the ad_hoc_dict representation is third. port, v = vs[:2] node.set_input(port, eval(v)) - if(len(vs)>2): + if (len(vs) > 2): d = MetaDataDict(vs[2]) node.input_desc[port].get_ad_hoc_dict().update(d) except: continue - return node def paste(self, cnode, data_modifiers=[], call_stack=None, meta=False): @@ -282,8 +283,8 @@ def paste(self, cnode, data_modifiers=[], call_stack=None, meta=False): # Apply modifiers (if callable) for (key, func) in data_modifiers: try: - if(callable(func)): - if(meta): + if (callable(func)): + if (meta): func(n) else: n.internal_data[key] = func(n.internal_data[key]) @@ -309,31 +310,33 @@ def paste(self, cnode, data_modifiers=[], call_stack=None, meta=False): def load_ad_hoc_data(self, node, elt_data, elt_ad_hoc=None): if elt_ad_hoc and len(elt_ad_hoc): - #reading 0.8+ files. + # reading 0.8+ files. d = MetaDataDict(dict=elt_ad_hoc) node.get_ad_hoc_dict().update(d) else: - #extracting ad hoc data from old files. - #we parse the Node class' __ad_hoc_from_old_map__ - #which defines conversions between new ad_hoc_dict keywords - #and old internal_data keywords. - #These dictionnaries are used to extend ad_hoc_dict of a node with the - #data that views expect. See node.initialise_standard_metadata() for an example. + # extracting ad hoc data from old files. + # we parse the Node class' __ad_hoc_from_old_map__ + # which defines conversions between new ad_hoc_dict keywords + # and old internal_data keywords. + # These dictionnaries are used to extend ad_hoc_dict of a node with the + # data that views expect. See node.initialise_standard_metadata() for an example. if hasattr(node, "__ad_hoc_from_old_map__"): for newKey, oldKeys in node.__ad_hoc_from_old_map__.iteritems(): - data = [] #list that stores the new values + data = [] # list that stores the new values _type, default = node.__ad_hoc_slots__.get(newKey) for key in oldKeys: data.append(elt_data.pop(key, None)) - if len(data) == 1 : data = data[0] - if data is None or (isinstance(data, list) and None in data): #? + if len(data) == 1: data = data[0] + if data is None or ( + isinstance(data, list) and None in data): # ? data = default - if data is None : continue + if data is None: continue node.get_ad_hoc_dict().set_metadata(newKey, _type(data)) - #finally put the internal data (elt_data) where it has always been expected. + # finally put the internal data (elt_data) where it has always been expected. node._init_internal_data(elt_data) -# node.internal_data.update(elt_data) + + # node.internal_data.update(elt_data) def instantiate_node(self, vid, call_stack=None): """ Partial instantiation @@ -349,7 +352,7 @@ def instantiate_node(self, vid, call_stack=None): node = factory.instantiate(call_stack) attributes = copy.deepcopy(self.elt_data[vid]) - ad_hoc = copy.deepcopy(self.elt_ad_hoc.get(vid, None)) + ad_hoc = copy.deepcopy(self.elt_ad_hoc.get(vid, None)) self.load_ad_hoc_data(node, attributes, ad_hoc) # copy node input data if any @@ -357,13 +360,14 @@ def instantiate_node(self, vid, call_stack=None): for vs in values: try: - #the two first elements are the historical - #values : port Id and port value - #the values beyond are not used. + # the two first elements are the historical + # values : port Id and port value + # the values beyond are not used. port, v = vs[:2] node.set_input(port, eval(v)) node.input_desc[port].get_ad_hoc_dict().set_metadata("hide", - node.is_port_hidden(port)) + node.is_port_hidden( + port)) except: continue @@ -373,7 +377,7 @@ def instantiate_node(self, vid, call_stack=None): # This shouldn't be here, it is related to visual stuff # ######################################################### def instantiate_widget(self, node=None, parent=None, \ - edit=False, autonomous=False): + edit=False, autonomous=False): """ Return the corresponding widget initialised with node @@ -381,11 +385,11 @@ def instantiate_widget(self, node=None, parent=None, \ widget composed with the node sub widget is returned. """ - if(edit): + if (edit): from openalea.visualea.dataflowview import GraphicalGraph return GraphicalGraph(node).create_view(parent) - if(node == None): + if (node == None): node = self.instantiate() from openalea.visualea.compositenode_widget import DisplayGraphWidget @@ -450,23 +454,23 @@ def set_io(self, inputs, outputs): # I/O ports # Remove node if nb of input has changed - if(self.id_in is not None - and len(inputs) != self.node(self.id_in).get_nb_output()): + if (self.id_in is not None + and len(inputs) != self.node(self.id_in).get_nb_output()): self.remove_node(self.id_in) self.id_in = None - if(self.id_out is not None - and len(outputs) != self.node(self.id_out).get_nb_input()): + if (self.id_out is not None + and len(outputs) != self.node(self.id_out).get_nb_input()): self.remove_node(self.id_out) self.id_out = None # Create new io node if necessary - if(self.id_in is None): + if (self.id_in is None): self.id_in = self.add_node(CompositeNodeInput(inputs)) else: self.node(self.id_in).set_io((), inputs) - if(self.id_out is None): + if (self.id_out is None): self.id_out = self.add_node(CompositeNodeOutput(outputs)) else: self.node(self.id_out).set_io(outputs, ()) @@ -491,28 +495,29 @@ def set_output(self, index_key, val): return self.node(self.id_out).set_output(index_key, val) - def get_eval_algo(self): + def get_eval_algo(self, record_provenance=False): """ Return the evaluation algo instance """ try: algo_str = self.eval_algo - algo_str = algo_str.strip('"'); + algo_str = algo_str.strip('"') algo_str = algo_str.strip("'") - # import module baseimp = "algo.dataflow_evaluation" module = __import__(baseimp, globals(), locals(), [algo_str]) classobj = module.__dict__[algo_str] - return classobj(self) + return classobj(self, record_provenance=record_provenance) except Exception, e: - from openalea.core.algo.dataflow_evaluation import DefaultEvaluation + from openalea.core.algo.dataflow_evaluation import \ + DefaultEvaluation return DefaultEvaluation(self) return self.eval_algo - def eval_as_expression(self, vtx_id=None, step=False): + def eval_as_expression(self, vtx_id=None, step=False, + record_provenance=False): """ Evaluate a vtx_id @@ -520,21 +525,25 @@ def eval_as_expression(self, vtx_id=None, step=False): """ import time t0 = time.time() - if(self.evaluating): + if self.evaluating: return - if(vtx_id != None): + if vtx_id is not None: self.node(vtx_id).modified = True - algo = self.get_eval_algo() + algo = self.get_eval_algo(record_provenance) try: self.evaluating = True - algo.eval(vtx_id,step=step) + algo.eval(vtx_id, step=step) finally: self.evaluating = False t1 = time.time() if quantify: - logger.info('Evaluation time: %s'%(t1-t0)) - print 'Evaluation time: %s'%(t1-t0) + logger.info('Evaluation time: %s' % (t1 - t0)) + print 'Evaluation time: %s' % (t1 - t0) + + if record_provenance: + return algo._prov + # Functions used by the node evaluator def eval(self, *args, **kwds): @@ -555,14 +564,14 @@ def __call__(self, inputs=()): Evaluate the graph """ - if(self.id_out and self.get_nb_output()>0): + if (self.id_out and self.get_nb_output() > 0): self.eval_as_expression(self.id_out) else: self.eval_as_expression(None) return () - def to_script (self) : + def to_script(self): """Translate the dataflow into a python script. """ from algo.dataflow_evaluation import ToScriptEvaluation @@ -585,16 +594,16 @@ def compute_external_io(self, vertex_selection, new_vid): self._compute_inout_connection(vertex_selection, is_input=False) in_edges = \ - self._compute_outside_connection(vertex_selection, in_edges, - new_vid, is_input=True) + self._compute_outside_connection(vertex_selection, in_edges, + new_vid, is_input=True) out_edges = \ self._compute_outside_connection(vertex_selection, out_edges, - new_vid, is_input=False) + new_vid, is_input=False) return in_edges + out_edges def _compute_outside_connection(self, vertex_selection, new_connections, - new_vid, is_input = True): + new_vid, is_input=True): """ Return external connections of a composite node with input and output ports. @@ -625,7 +634,7 @@ def _compute_outside_connection(self, vertex_selection, new_connections, for edge in new_connections: if is_input: - if(edge[0] != '__in__'): + if (edge[0] != '__in__'): continue target_id, target_port = edge[2:] if (target_id, target_port) in selected_port: @@ -635,7 +644,7 @@ def _compute_outside_connection(self, vertex_selection, new_connections, port_id = self.local_id(self.source_port(e)) connections.append((vid, port_id, new_vid, edge[1])) else: - if(edge[2] != '__out__'): + if (edge[2] != '__out__'): continue source_id, source_port = edge[0:2] @@ -690,7 +699,7 @@ def _compute_inout_connection(self, vertex_selection, is_input=True): n = self.node(vid) desc = dict(io_desc(n)[pname]) - caption= '(%s)' % (n.get_caption()) + caption = '(%s)' % (n.get_caption()) count = '' name = desc['name'] @@ -719,7 +728,7 @@ def _compute_inout_connection(self, vertex_selection, is_input=True): desc['value'] = desc['interface'].default() connections.append(('__in__', len(nodes), vid, pname)) - else: # output + else: # output connections.append((vid, pname, '__out__', len(nodes))) nodes.append(desc) @@ -734,7 +743,6 @@ def compute_io(self, v_list=None): v_list is a vertex id list """ - ins, in_edges = self._compute_inout_connection(v_list, is_input=True) outs, out_edges = \ self._compute_inout_connection(v_list, is_input=False) @@ -742,7 +750,7 @@ def compute_io(self, v_list=None): return (ins, outs, connections) - def to_factory(self, sgfactory, listid = None, auto_io=False): + def to_factory(self, sgfactory, listid=None, auto_io=False): """ Update CompositeNodeFactory to fit with the graph @@ -757,9 +765,9 @@ def to_factory(self, sgfactory, listid = None, auto_io=False): # Properties sgfactory.lazy = self.lazy sgfactory.eval_algo = self.eval_algo - #print self.eval_algo + # print self.eval_algo # I / O - if(auto_io): + if (auto_io): (ins, outs, sup_connect) = self.compute_io(listid) sgfactory.inputs = ins sgfactory.outputs = outs @@ -777,11 +785,11 @@ def to_factory(self, sgfactory, listid = None, auto_io=False): src = self.source(eid) tgt = self.target(eid) - if((src not in listid) or (tgt not in listid)): + if ((src not in listid) or (tgt not in listid)): continue - if(src == self.id_in): + if (src == self.id_in): src = '__in__' - if(tgt == self.id_out): + if (tgt == self.id_out): tgt = '__out__' source_port = self.local_id(self.source_port(eid)) @@ -800,9 +808,9 @@ def to_factory(self, sgfactory, listid = None, auto_io=False): kdata = node.internal_data # Do not copy In and Out - if(vid == self.id_in): + if (vid == self.id_in): vid = "__in__" - elif(vid == self.id_out): + elif (vid == self.id_out): vid = "__out__" else: pkg_id = node.factory.package.get_id() @@ -815,10 +823,11 @@ def to_factory(self, sgfactory, listid = None, auto_io=False): # We do the exact opposite than in load_ad_hoc_data, have a look there. if hasattr(node, "__ad_hoc_from_old_map__"): for newKey, oldKeys in node.__ad_hoc_from_old_map__.iteritems(): - if len(oldKeys)==0: continue + if len(oldKeys) == 0: continue data = node.get_ad_hoc_dict().get_metadata(newKey) for pos, newKey in enumerate(oldKeys): - sgfactory.elt_data[vid][newKey] = data[pos] if isinstance(data, list) else data + sgfactory.elt_data[vid][newKey] = data[ + pos] if isinstance(data, list) else data # Copy ad_hoc data sgfactory.elt_ad_hoc[vid] = copy.deepcopy(node.get_ad_hoc_dict()) @@ -835,10 +844,10 @@ def to_factory(self, sgfactory, listid = None, auto_io=False): self.graph_modified = False # Set node factory if all node have been exported - if(listid is None): + if (listid is None): self.factory = sgfactory - def add_node(self, node, vid = None, modify=True): + def add_node(self, node, vid=None, modify=True): """ Add a node in the Graph with a particular id if id is None, autogenrate one @@ -863,9 +872,9 @@ def add_node(self, node, vid = None, modify=True): self.set_actor(vid, node) self.notify_vertex_addition(node, vid) - #self.id_cpt += 1 - if(modify): - self.notify_listeners(("graph_modified", )) + # self.id_cpt += 1 + if (modify): + self.notify_listeners(("graph_modified",)) self.graph_modified = True return vid @@ -873,24 +882,30 @@ def add_node(self, node, vid = None, modify=True): def notify_vertex_addition(self, vertex, vid=None): vtype = "vertex" doNotify = True - if(vertex.__class__.__dict__.has_key("__graphitem__")): vtype = "annotation" + if (vertex.__class__.__dict__.has_key("__graphitem__")): + vtype = "annotation" elif isinstance(vertex, CompositeNodeOutput): vtype = "outNode" doNotify = True if len(vertex.input_desc) else False - elif isinstance(vertex, CompositeNodeInput) : + elif isinstance(vertex, CompositeNodeInput): vtype = "inNode" doNotify = True if len(vertex.output_desc) else False - else: pass + else: + pass if doNotify: self.notify_listeners(("vertex_added", (vtype, vertex))) def notify_vertex_removal(self, vertex): vtype = "vertex" doNotify = True - if(vertex.__class__.__dict__.has_key("__graphitem__")): vtype = "annotation" - elif isinstance(vertex, CompositeNodeOutput): vtype = "outNode" - elif isinstance(vertex, CompositeNodeInput) : vtype = "inNode" - else: pass + if (vertex.__class__.__dict__.has_key("__graphitem__")): + vtype = "annotation" + elif isinstance(vertex, CompositeNodeOutput): + vtype = "outNode" + elif isinstance(vertex, CompositeNodeInput): + vtype = "inNode" + else: + pass self.notify_listeners(("vertex_removed", (vtype, vertex))) def remove_node(self, vtx_id): @@ -899,12 +914,14 @@ def remove_node(self, vtx_id): :param vtx_id: element id """ node = self.node(vtx_id) - if vtx_id == self.id_in : self.id_in = None - elif vtx_id == self.id_out : self.id_out = None + if vtx_id == self.id_in: + self.id_in = None + elif vtx_id == self.id_out: + self.id_out = None self.remove_vertex(vtx_id) node.close() self.notify_vertex_removal(node) - self.notify_listeners(("graph_modified", )) + self.notify_listeners(("graph_modified",)) self.graph_modified = True def remove_edge(self, eid): @@ -915,9 +932,9 @@ def remove_edge(self, eid): port = None DataFlow.remove_edge(self, eid) if port: - self.actor(port._vid).set_input_state(port._local_pid, "disconnected") - self.notify_listeners(("edge_removed", ("default",eid) )) - + self.actor(port._vid).set_input_state(port._local_pid, + "disconnected") + self.notify_listeners(("edge_removed", ("default", eid))) def simulate_destruction_notifications(self): """emits messages as if we were adding elements to @@ -931,7 +948,7 @@ def simulate_destruction_notifications(self): for eid in self.edges(): (src_id, dst_id) = self.source(eid), self.target(eid) - etype=None + etype = None src_port_id = self.local_id(self.source_port(eid)) dst_port_id = self.local_id(self.target_port(eid)) @@ -940,10 +957,10 @@ def simulate_destruction_notifications(self): src_port = nodeSrc.output_desc[src_port_id] dst_port = nodeDst.input_desc[dst_port_id] - #don't notify if the edge is connected to the input or - #output nodes. + # don't notify if the edge is connected to the input or + # output nodes. # if(src_id == self.id_in or dst_id == self.id_out): - # continue + # continue edgedata = "default", eid self.notify_listeners(("edge_removed", edgedata)) @@ -962,11 +979,12 @@ def connect(self, src_id, port_src, dst_id, port_dst): target_pid = self.in_port(dst_id, port_dst) eid = DataFlow.connect(self, source_pid, target_pid) except: - logger.error("Enable to create the edge %s %d %d %d %d"%( self.factory.name, src_id, port_src, dst_id, port_dst)) + logger.error("Enable to create the edge %s %d %d %d %d" % ( + self.factory.name, src_id, port_src, dst_id, port_dst)) return self.actor(dst_id).set_input_state(port_dst, "connected") - self.notify_listeners(("connection_modified", )) + self.notify_listeners(("connection_modified",)) self.graph_modified = True self.update_eval_listeners(src_id) @@ -976,8 +994,8 @@ def connect(self, src_id, port_src, dst_id, port_dst): dst_port = nodeDst.input_desc[port_dst] edgedata = "default", eid, src_port, dst_port - #connected ports cannot be hidden: - #nodeSrc.set_port_hidden(port_src, False) + # connected ports cannot be hidden: + # nodeSrc.set_port_hidden(port_src, False) nodeDst.set_port_hidden(port_dst, False) self.notify_listeners(("edge_added", edgedata)) @@ -996,10 +1014,10 @@ def disconnect(self, src_id, port_src, dst_id, port_dst): for eid in self.connected_edges(source_pid): if self.target_port(eid) == target_pid: - self.notify_listeners(("edge_removed", ("default",eid))) + self.notify_listeners(("edge_removed", ("default", eid))) self.remove_edge(eid) self.actor(dst_id).set_input_state(port_dst, "disconnected") - self.notify_listeners(("connection_modified", )) + self.notify_listeners(("connection_modified",)) self.graph_modified = True self.update_eval_listeners(src_id) @@ -1016,8 +1034,8 @@ def replace_node(self, vid, newnode): # newnode.internal_data.update(oldnode.internal_data) newnode.caption = caption - if(oldnode.get_nb_input() != newnode.get_nb_input() or - oldnode.get_nb_output() != newnode.get_nb_output()): + if (oldnode.get_nb_input() != newnode.get_nb_input() or + oldnode.get_nb_output() != newnode.get_nb_output()): raise IncompatibleNodeError() self.set_actor(vid, newnode) @@ -1029,11 +1047,11 @@ def set_continuous_eval(self, vid, state=True): node = self.actor(vid) - if(not node.user_application and not state): + if (not node.user_application and not state): return # Remove previous listener - if(node.user_application and hasattr(node, 'continuous_listener')): + if (node.user_application and hasattr(node, 'continuous_listener')): listener = node.continuous_listener node.continuous_listener = None if listener: @@ -1041,7 +1059,7 @@ def set_continuous_eval(self, vid, state=True): node.user_application = state - if(state): + if (state): listener = ContinuousEvalListener(self, vid) node.continuous_listener = listener @@ -1067,6 +1085,7 @@ def update_eval_listeners(self, vid): listeners = dst_node.continuous_eval.listeners src_node.continuous_eval.listeners.update(listeners) + from openalea.core.observer import AbstractListener @@ -1109,7 +1128,7 @@ def get_input(self, input_pid): def eval(self): return False - def to_script (self): + def to_script(self): return "" @@ -1138,7 +1157,7 @@ def set_output(self, output_pid, val): def eval(self): return False - def to_script (self): + def to_script(self): return "" @@ -1147,7 +1166,8 @@ class PyCNFactoryWriter(object): sgfactory_template = """ -$NAME = CompositeNodeFactory(name=$PNAME, +$NAME = CompositeNodeFactory(uid=$UID, + name=$PNAME, description=$DESCRIPTION, category=$CATEGORY, doc=$DOC, @@ -1179,15 +1199,19 @@ def __repr__(self): name = f.get_python_name() name = name.replace('.', '_') - result = fstr.safe_substitute(NAME=name, + result = fstr.safe_substitute(UID=self.pprint_repr(f.uid), + NAME=name, PNAME=self.pprint_repr(f.name), - DESCRIPTION=self.pprint_repr(f.description), + DESCRIPTION=self.pprint_repr( + f.description), CATEGORY=self.pprint_repr(f.category), DOC=self.pprint_repr(f.doc), INPUTS=self.pprint_repr(f.inputs), OUTPUTS=self.pprint_repr(f.outputs), - ELT_FACTORY=self.pprint_repr(f.elt_factory), - ELT_CONNECTIONS=self.pprint_repr(f.connections), + ELT_FACTORY=self.pprint_repr( + f.elt_factory), + ELT_CONNECTIONS=self.pprint_repr( + f.connections), ELT_DATA=self.pprint_repr(f.elt_data), ELT_VALUE=self.pprint_repr(f.elt_value), ELT_AD_HOC=self.pprint_repr(f.elt_ad_hoc), @@ -1196,14 +1220,18 @@ def __repr__(self): ) return result + import json -class JSONCNFactoryWriter(PyCNFactoryWriter): + +class JSONCNFactoryWriter(PyCNFactoryWriter): def __repr__(self): f = self.factory - minx = min(f.elt_ad_hoc.itervalues(), key=lambda x: x["position"][0])["position"][0] - miny = min(f.elt_ad_hoc.itervalues(), key=lambda x: x["position"][1])["position"][1] + minx = min(f.elt_ad_hoc.itervalues(), key=lambda x: x["position"][0])[ + "position"][0] + miny = min(f.elt_ad_hoc.itervalues(), key=lambda x: x["position"][1])[ + "position"][1] print minx, miny @@ -1216,12 +1244,12 @@ def __repr__(self): description=f.description, category=f.category, doc=f.doc, - #inputs=f.inputs, - #outputs=f.outputs, - #elt_factory=f.elt_factory, + # inputs=f.inputs, + # outputs=f.outputs, + # elt_factory=f.elt_factory, elt_connections=list(f.connections.itervalues()), - #elt_data=f.elt_data, - #elt_value=f.elt_value, + # elt_data=f.elt_data, + # elt_value=f.elt_value, elt_ad_hoc=f.elt_ad_hoc, lazy=f.lazy, eval_algo=f.eval_algo, diff --git a/src/openalea/core/interface.py b/src/openalea/core/interface.py index fa085ad8..915efed3 100644 --- a/src/openalea/core/interface.py +++ b/src/openalea/core/interface.py @@ -193,6 +193,13 @@ class ICodeStr(IStr): pass +class IRef(IStr): + """Interface for uids + """ + __label__ = u'ref' + pass + + class IFloat(IInterface): """ Float interface """ diff --git a/src/openalea/core/metadatadict.py b/src/openalea/core/metadatadict.py index 41e9d5a9..6a641e0d 100644 --- a/src/openalea/core/metadatadict.py +++ b/src/openalea/core/metadatadict.py @@ -84,6 +84,18 @@ def __repr__(self): def __len__(self): return len(self._metaTypes) + def get(self, key, default=None): + """Subclass of dict.get method + + Args: + key (any): + default (any): + + Returns: + (any) + """ + return self._metaValues.get(key, default) + def add_metadata(self, key, valType, notify=True): """Creates a new entry in the meta data registry. The data to set will be of the given 'valType' type.""" diff --git a/src/openalea/core/node.py b/src/openalea/core/node.py index 3a46c531..b2ec01db 100644 --- a/src/openalea/core/node.py +++ b/src/openalea/core/node.py @@ -24,13 +24,14 @@ __license__ = "Cecill-C" __revision__ = " $Id$ " +from copy import copy, deepcopy import imp import inspect import os import sys import string import types -from copy import copy, deepcopy +from uuid import uuid1 from weakref import ref, proxy # from signature import get_parameters @@ -39,8 +40,10 @@ from actor import IActor from metadatadict import MetaDataDict, HasAdHoc from interface import TypeNameInterfaceMap + + # Exceptions -class RecursionError (Exception): +class RecursionError(Exception): """todo""" pass @@ -110,7 +113,7 @@ def set_compositenode(self, upper): def set_data(self, key, value, notify=True): """ Set internal node data """ self.internal_data[key] = value - if(notify): + if (notify): self.notify_listeners(("data_modified", key, value)) def close(self): @@ -199,7 +202,7 @@ def get_tip(self, current_value=None): desc = self.get('desc', '') value = self.get('value', None) iname = 'Any' - if(interface): + if (interface): try: iname = interface.__name__ except AttributeError: @@ -213,9 +216,9 @@ def get_tip(self, current_value=None): if len(comment) > 100: comment = comment[:100] + ' ...' - if current_value is None : + if current_value is None: return '%s(%s): %s [default=%s] ' % (name, iname, desc, comment) - else : + else: return '%s(%s): %s' % (name, iname, str(current_value)) @@ -236,6 +239,7 @@ def is_hidden(self): class OutputPort(AbstractPort): """The class describing the output ports """ + def __init__(self, node): AbstractPort.__init__(self, node) @@ -244,11 +248,12 @@ class Annotation(AbstractNode): def __init__(self): AbstractNode.__init__(self) - def to_script (self): + def to_script(self): """Script translation of this node. """ return "" + class Node(AbstractNode): """ It is a callable object with typed inputs and outputs. @@ -293,11 +298,11 @@ def __init__(self, inputs=(), outputs=()): self.modified = True # Internal Data - self.internal_data["caption"] = '' # str(self.__class__.__name__) + self.internal_data["caption"] = '' # str(self.__class__.__name__) self.internal_data["lazy"] = True - self.internal_data["block"] = False # Do not evaluate the node + self.internal_data["block"] = False # Do not evaluate the node self.internal_data["priority"] = 0 - self.internal_data["hide"] = True # hide in composite node widget + self.internal_data["hide"] = True # hide in composite node widget self.internal_data["port_hide_changed"] = set() # Add delay self.internal_data["delay"] = 0 @@ -400,7 +405,8 @@ def get_user_application(self): def set_user_application(self, data): """todo""" self.internal_data["user_application"] = data - self.notify_listeners(("internal_data_changed", "user_application", data)) + self.notify_listeners( + ("internal_data_changed", "user_application", data)) user_application = property(get_user_application, set_user_application) @@ -418,12 +424,12 @@ def get_caption(self): def is_port_hidden(self, index_key): """ Return the hidden state of a port """ index = self.map_index_in[index_key] - s = self.input_desc[index].is_hidden() # get('hide', False) + s = self.input_desc[index].is_hidden() # get('hide', False) changed = self.internal_data["port_hide_changed"] c = index in changed - if(index in changed): + if (index in changed): return not s else: return s @@ -436,7 +442,7 @@ def set_port_hidden(self, index_key, state): :param state: a boolean value. """ index = self.map_index_in[index_key] - s = self.input_desc[index].is_hidden() # get('hide', False) + s = self.input_desc[index].is_hidden() # get('hide', False) changed = self.internal_data["port_hide_changed"] @@ -444,12 +450,11 @@ def set_port_hidden(self, index_key, state): changed.add(index) self.input_desc[index].get_ad_hoc_dict().set_metadata("hide", state) self.notify_listeners(("hiddenPortChange",)) - elif(index in changed): + elif (index in changed): changed.remove(index) self.input_desc[index].get_ad_hoc_dict().set_metadata("hide", state) self.notify_listeners(("hiddenPortChange",)) - # Status def unvalidate_input(self, index_key, notify=True): """ @@ -459,7 +464,7 @@ def unvalidate_input(self, index_key, notify=True): """ self.modified = True index = self.map_index_in[index_key] - if(notify): + if (notify): self.notify_listeners(("input_modified", index)) self.continuous_eval.notify_listeners(("node_modified",)) @@ -473,13 +478,13 @@ def set_io(self, inputs, outputs): """ # # Values - if(inputs is None or len(inputs) != len(self.inputs)): + if (inputs is None or len(inputs) != len(self.inputs)): self.clear_inputs() if inputs: for d in inputs: self.add_input(**d) - if(outputs is None or len(outputs) != len(self.outputs)): + if (outputs is None or len(outputs) != len(self.outputs)): self.clear_outputs() if outputs: for d in outputs: @@ -508,7 +513,6 @@ def clear_outputs(self): self.map_index_out = {} self.notify_listeners(("cleared_output_ports",)) - def add_input(self, **kargs): """ Create an input port """ @@ -517,7 +521,7 @@ def add_input(self, **kargs): interface = kargs.get('interface', None) # default value - if(interface and not kargs.has_key('value')): + if (interface and not kargs.has_key('value')): if isinstance(interface, str): # Create mapping between interface name and interface class from openalea.core.interface import TypeNameInterfaceMap @@ -530,7 +534,7 @@ def add_input(self, **kargs): value = copy(value) - name = str(name) # force to have a string + name = str(name) # force to have a string self.inputs.append(None) port = InputPort(self) @@ -575,14 +579,14 @@ def set_input(self, key, val=None, notify=True): index = self.map_index_in[key] changed = True - if(self.lazy): + if (self.lazy): # Test if the inputs has changed try: changed = (cmp(self.inputs[index], val) != 0) except: pass - if(changed): + if (changed): self.inputs[index] = val self.unvalidate_input(index, notify) @@ -636,7 +640,8 @@ def eval(self): and a timed delay if the node needs a reevaluation at a later time. """ # lazy evaluation - if self.block and self.get_nb_output() != 0 and self.output(0) is not None: + if self.block and self.get_nb_output() != 0 and self.output( + 0) is not None: return False if (self.delay == 0 and self.lazy) and not self.modified: return False @@ -659,9 +664,9 @@ def eval(self): self.output_desc[0].notify_listeners(("tooltip_modified",)) - else: # multi output - if(not isinstance(outlist, tuple) and - not isinstance(outlist, list)): + else: # multi output + if (not isinstance(outlist, tuple) and + not isinstance(outlist, list)): outlist = (outlist,) for i in range(min(len(outlist), len(self.outputs))): @@ -684,7 +689,6 @@ def __getstate__(self): odict['modified'] = True - outputs = range(len(self.outputs)) for i in range(self.get_nb_output()): try: @@ -737,7 +741,7 @@ def reload(self): # if(not connected or self.input_states[i] is "connected"): self.set_input(i, self.input_desc[i].get('value', None)) - if(i > 0): + if (i > 0): self.invalidate() def reset(self): @@ -747,7 +751,7 @@ def reset(self): i = self.get_nb_input() - if(i > 0): + if (i > 0): self.invalidate() def invalidate(self): @@ -758,16 +762,16 @@ def invalidate(self): self.continuous_eval.notify_listeners(("node_modified", self)) -# X @property -# X def outputs(self): -# X return [self.output(i) for i in range(self.get_nb_output())] + # X @property + # X def outputs(self): + # X return [self.output(i) for i in range(self.get_nb_output())] - def to_script (self): + def to_script(self): """Script translation of this node. """ - if self._to_script_func is None : + if self._to_script_func is None: return "#node %s do not define any scripting\n" % self.factory.name - else : + else: return self._to_script_func(self.inputs, self.outputs) @@ -787,7 +791,7 @@ def __init__(self, inputs, outputs, func): def __call__(self, inputs=()): """ Call function. Must be overriden """ - if(self.func): + if (self.func): return self.func(*inputs) def get_process_obj(self): @@ -838,6 +842,7 @@ def __init__(self, Observed.__init__(self) # Factory info + self.uid = kargs.get("uid", uuid1().hex) self.name = name self.description = description self.category = category @@ -853,6 +858,7 @@ def __init__(self, self.delay = delay self.alias = alias self.authors = authors + # Package property def set_pkg(self, port): @@ -862,7 +868,7 @@ def set_pkg(self, port): The package id is the name of the package when the package is the Python object. """ - if(not port): + if (not port): self.__pkg__ = None self.__pkg_id = None else: @@ -873,13 +879,13 @@ def set_pkg(self, port): def get_pkg(self): """todo""" - if(self.__pkg__): + if (self.__pkg__): port = self.__pkg__() else: port = None # Test if pkg has been reloaded # In this case the weakref is not valid anymore - if(not port and self.__pkg_id__): + if (not port and self.__pkg_id__): from openalea.core.pkgmanager import PackageManager port = self.set_pkg(PackageManager()[self.__pkg_id__]) return port @@ -908,7 +914,7 @@ def get_python_name(self): name = self.name - if(not name.isalnum()): + if (not name.isalnum()): name = '_%s' % (id(self)) return name @@ -931,7 +937,6 @@ def get_tip(self, asRst=False): found in its package. """ - if not asRst: return "Name: %s
" % (self.name,) + \ "Category: %s
" % (self.category,) + \ @@ -954,7 +959,7 @@ def instantiate(self, call_stack=[]): raise NotImplementedError() def instantiate_widget(self, node=None, parent=None, edit=False, - autonomous=False): + autonomous=False): """ Return the corresponding widget initialised with node""" raise NotImplementedError() @@ -991,8 +996,8 @@ def is_composite_node(self): return False def __getstate__(self): - odict = self.__dict__.copy() # copy the dict since we change it - odict['__pkg__'] = None # remove weakref reference + odict = self.__dict__.copy() # copy the dict since we change it + odict['__pkg__'] = None # remove weakref reference return odict def __setstate__(self, dict): @@ -1002,7 +1007,7 @@ def __setstate__(self, dict): def Alias(factory, name): """ Create a alias for factory """ - if(factory.alias is None): + if (factory.alias is None): factory.alias = [name] else: factory.alias.append(name) @@ -1063,7 +1068,7 @@ def __init__(self, # Module path, value=0 self.nodemodule_path = None - if(not search_path): + if (not search_path): self.search_path = [] else: self.search_path = search_path @@ -1073,19 +1078,17 @@ def __init__(self, # Context directory # inspect.stack()[1][1] is the caller python module caller_dir = os.path.dirname(os.path.abspath(inspect.stack()[1][1])) - if(not caller_dir in self.search_path): + if (not caller_dir in self.search_path): self.search_path.append(caller_dir) - def is_node(self): return True def get_python_name(self): """ Return a python valid name """ - module_name = self.nodemodule_name - module_name = module_name.replace('.','_') - return "%s_%s" % (self.nodemodule_name, self.nodeclass_name) + module_name = self.nodemodule_name.replace('.', '_') + return "%s_%s" % (module_name, self.nodeclass_name) def __getstate__(self): """ Pickle function """ @@ -1094,7 +1097,7 @@ def __getstate__(self): odict['nodemodule'] = None odict['nodeclass'] = None odict['module_cache'] = None - odict['__pkg__'] = None # remove weakref reference + odict['__pkg__'] = None # remove weakref reference return odict @@ -1132,22 +1135,21 @@ def instantiate(self, call_stack=[]): if classobj is None: raise Exception("Cannot instantiate '" + \ - self.nodeclass_name + "' from " + str(module)) + self.nodeclass_name + "' from " + str(module)) # If class is not a Node, embed object in a Node class - if(not hasattr(classobj, 'mro') or not AbstractNode in classobj.mro()): + if (not hasattr(classobj, 'mro') or not AbstractNode in classobj.mro()): # Check inputs and outputs - if(self.inputs is None): + if (self.inputs is None): sign = sgn.Signature(classobj) self.inputs = sign.get_parameters() - if(self.outputs is None): + if (self.outputs is None): self.outputs = (dict(name="out", interface=None),) - # Check and Instantiate if we have a functor class - if((type(classobj) == types.TypeType) - or (type(classobj) == types.ClassType)): + if ((type(classobj) == types.TypeType) + or (type(classobj) == types.ClassType)): _classobj = classobj() if callable(_classobj): @@ -1166,7 +1168,7 @@ def instantiate(self, call_stack=[]): try: node.factory = self node.lazy = self.lazy - if(not node.caption): + if (not node.caption): node.set_caption(self.name) node.delay = self.delay @@ -1174,17 +1176,18 @@ def instantiate(self, call_stack=[]): pass # to script - if self.toscriptclass_name is not None : - node._to_script_func = module.__dict__.get(self.toscriptclass_name, None) + if self.toscriptclass_name is not None: + node._to_script_func = module.__dict__.get(self.toscriptclass_name, + None) return node def instantiate_widget(self, node=None, parent=None, - edit=False, autonomous=False): + edit=False, autonomous=False): """ Return the corresponding widget initialised with node """ # Code Editor - if(edit): + if (edit): from openalea.visualea.code_editor import get_editor w = get_editor()(parent) try: @@ -1199,15 +1202,15 @@ def instantiate_widget(self, node=None, parent=None, return w # Node Widget - if(node == None): + if (node == None): node = self.instantiate() modulename = self.widgetmodule_name - if(not modulename): + if (not modulename): modulename = self.nodemodule_name # if no widget declared, we create a default one - if(not modulename or not self.widgetclass_name): + if (not modulename or not self.widgetclass_name): from openalea.visualea.node_widget import DefaultNodeWidget return DefaultNodeWidget(node, parent, autonomous) @@ -1215,13 +1218,13 @@ def instantiate_widget(self, node=None, parent=None, else: # load module (file, pathname, desc) = imp.find_module(modulename, - self.search_path + sys.path) + self.search_path + sys.path) sys.path.append(os.path.dirname(pathname)) module = imp.load_module(modulename, file, pathname, desc) sys.path.pop() - if(file): + if (file): file.close() widgetclass = module.__dict__[self.widgetclass_name] @@ -1244,8 +1247,8 @@ def get_node_module(self): # Test if the module is already in sys.modules if (self.nodemodule_path and - self.module_cache and - not hasattr(self.module_cache, 'oa_invalidate')): + self.module_cache and + not hasattr(self.module_cache, 'oa_invalidate')): return self.module_cache sav_path = sys.path @@ -1290,7 +1293,6 @@ def get_node_file(self): self.get_node_module() return self.nodemodule_path - def get_node_src(self, cache=True): """ Return a string containing the node src @@ -1299,7 +1301,7 @@ def get_node_src(self, cache=True): """ # Return cached source if any - if(self.src_cache and cache): + if (self.src_cache and cache): return self.src_cache module = self.get_node_module() @@ -1338,20 +1340,19 @@ def save_new_src(self, newsrc): modulesrc = inspect.getsource(module) # Pass if no modications - if(nodesrc == newsrc): + if (nodesrc == newsrc): return # replace old code with new one modulesrc = modulesrc.replace(nodesrc, newsrc) - # write file myfile = open(self.nodemodule_path, 'w') myfile.write(modulesrc) myfile.close() # reload module - if(self.module_cache): + if (self.module_cache): self.module_cache.invalidate_oa = True self.src_cache = None @@ -1361,6 +1362,7 @@ def save_new_src(self, newsrc): # import py_compile # py_compile.compile(self.nodemodule_path) + # Class Factory: Factory = NodeFactory @@ -1370,7 +1372,8 @@ class PyNodeFactoryWriter(object): nodefactory_template = """ -$NAME = Factory(name=$PNAME, +$NAME = Factory(uid=$UID, + name=$PNAME, authors=$AUTHORS, description=$DESCRIPTION, category=$CATEGORY, @@ -1391,10 +1394,11 @@ def __repr__(self): """ Return the python string representation """ f = self.factory fstr = string.Template(self.nodefactory_template) - + name = f.get_python_name() name = name.replace('.', '_') - result = fstr.safe_substitute(NAME=name, + result = fstr.safe_substitute(UID=repr(f.uid), + NAME=name, AUTHORS=repr(f.get_authors()), PNAME=repr(f.name), DESCRIPTION=repr(f.description), @@ -1404,9 +1408,10 @@ def __repr__(self): LISTIN=repr(f.inputs), LISTOUT=repr(f.outputs), WIDGETMODULE=repr(f.widgetmodule_name), - WIDGETCLASS=repr(f.widgetclass_name),) + WIDGETCLASS=repr(f.widgetclass_name), ) return result + # Utility functions def gen_port_list(size): """ Generate a list of port description """ @@ -1421,15 +1426,15 @@ def initialise_standard_metadata(): # we declare what are the node model ad hoc data we require: AbstractNode.extend_ad_hoc_slots("position", list, [0, 0], "posx", "posy") Node.extend_ad_hoc_slots("userColor", list, None, "user_color") - Node.extend_ad_hoc_slots("useUserColor", bool, True, "use_user_color",) + Node.extend_ad_hoc_slots("useUserColor", bool, True, "use_user_color", ) Annotation.extend_ad_hoc_slots("text", str, "", "txt") -# Annotation.extend_ad_hoc_slots("htmlText", str, None) + # Annotation.extend_ad_hoc_slots("htmlText", str, None) Annotation.extend_ad_hoc_slots("textColor", list, None) Annotation.extend_ad_hoc_slots("rectP2", tuple, (-1, -1)) Annotation.extend_ad_hoc_slots("color", list, None) Annotation.extend_ad_hoc_slots("visualStyle", int, None) # we declare what are the node model ad hoc data we require: - AbstractPort.extend_ad_hoc_slots("hide" , bool, False) + AbstractPort.extend_ad_hoc_slots("hide", bool, False) AbstractPort.extend_ad_hoc_slots("connectorPosition", list, [0, 0]) diff --git a/src/openalea/core/system/__wralea__.py b/src/openalea/core/system/__wralea__.py index dd3c02ff..bda144ec 100644 --- a/src/openalea/core/system/__wralea__.py +++ b/src/openalea/core/system/__wralea__.py @@ -15,12 +15,12 @@ # ############################################################################### """Wralea for System nodes""" -__revision__ = " $Id$ " - -from openalea.core.external import * #IGNORE:W0614 +from openalea.core import Factory as Fa +from openalea.core import IBool, IFunction, IInt, ISequence, IStr from openalea.core.pkgdict import protected +__revision__ = " $Id$ " __name__ = "openalea.flow control" __alias__ = ["system"] @@ -33,268 +33,247 @@ __all__ = [] -annotation = Factory(name="annotation", - description="Annotation", - category="flow control", - nodemodule="openalea.core.system.systemnodes", - nodeclass="AnnotationNode", - ) +annotation = Fa(uid="3b4eb8dc4e7d11e6bff6d4bed973e64a", + name="annotation", + description="Annotation", + category="flow control", + nodemodule="openalea.core.system.systemnodes", + nodeclass="AnnotationNode", + ) __all__.append('annotation') -iter = Factory(name="iter", - description="Iteration", - category="System", - nodemodule="openalea.core.system.systemnodes", - nodeclass="IterNode", - inputs = (dict(name="generator", interface=None, value=None), - ), - outputs = ( dict(name="value", interface=None), ), - - ) -__all__.append('iter') - -iter_with_delay = Factory(name="iter with delay", - description="Iteration ", - category="flow control", - nodemodule="openalea.core.system.systemnodes", - nodeclass="IterWithDelayNode", - inputs = (dict(name="generator", interface=None, value=None), - dict(name="delay", interface=IInt, value=1), - ), - outputs = ( dict(name="value", interface=None), ), - - ) +iter_ = Fa(uid="3b4eb8dd4e7d11e6bff6d4bed973e64a", + name="iter", + description="Iteration", + category="System", + nodemodule="openalea.core.system.systemnodes", + nodeclass="IterNode", + inputs=(dict(name="generator", interface=None, value=None), + ), + outputs=(dict(name="value", interface=None),), + + ) +__all__.append('iter_') + +iter_with_delay = Fa(uid="3b4eb8de4e7d11e6bff6d4bed973e64a", + name="iter with delay", + description="Iteration ", + category="flow control", + nodemodule="openalea.core.system.systemnodes", + nodeclass="IterWithDelayNode", + inputs=(dict(name="generator", interface=None, value=None), + dict(name="delay", interface=IInt, value=1), + ), + outputs=(dict(name="value", interface=None),), + + ) __all__.append('iter_with_delay') -counter = Factory(name="counter", - description="Count from start to stop, step by step ", - category="flow control", - nodemodule="openalea.core.system.systemnodes", - nodeclass="Counter", - inputs = (dict(name="start", interface=IInt, value=0), - dict(name="stop", interface=IInt, value=10), - dict(name="step", interface=IInt, value=1), - dict(name="dummy", interface=None), - ), - outputs = ( dict(name="value", interface=IInt), ), - delay = 1, - ) +counter = Fa(uid="3b4eb8df4e7d11e6bff6d4bed973e64a", + name="counter", + description="Count from start to stop, step by step ", + category="flow control", + nodemodule="openalea.core.system.systemnodes", + nodeclass="Counter", + inputs=(dict(name="start", interface=IInt, value=0), + dict(name="stop", interface=IInt, value=10), + dict(name="step", interface=IInt, value=1), + dict(name="dummy", interface=None), + ), + outputs=(dict(name="value", interface=IInt),), + delay=1, + ) __all__.append('counter') -stop_simulation = Factory(name="stop simulation", - description="Iteration ", - category="flow control", - nodemodule="openalea.core.system.systemnodes", - nodeclass="StopSimulation", - inputs = (dict(name="any object"), - dict(name="max nb cycles", interface=IInt, value=10), - ), - outputs = ( dict(name="any"), ), - - ) +stop_simulation = Fa(uid="3b4eb8e04e7d11e6bff6d4bed973e64a", + name="stop simulation", + description="Iteration ", + category="flow control", + nodemodule="openalea.core.system.systemnodes", + nodeclass="StopSimulation", + inputs=(dict(name="any object"), + dict(name="max nb cycles", interface=IInt, + value=10), + ), + outputs=(dict(name="any"),), + + ) __all__.append('stop_simulation') -rdv = Factory(name="rendez vous", - description="Synchronize 2 inputs", - category="flow control", - nodemodule="openalea.core.system.systemnodes", - nodeclass="RDVNode", - inputs = (dict(name="value", interface=None, value=None), - dict(name="control_flow", interface=None, value=None), - ), - outputs = ( dict(name="value", interface=None), - dict(name="flow result", interface=None),), +rdv = Fa(uid="3b4eb8e14e7d11e6bff6d4bed973e64a", + name="rendez vous", + description="Synchronize 2 inputs", + category="flow control", + nodemodule="openalea.core.system.systemnodes", + nodeclass="RDVNode", + inputs=(dict(name="value", interface=None, value=None), + dict(name="control_flow", interface=None, value=None), + ), + outputs=(dict(name="value", interface=None), + dict(name="flow result", interface=None),), - ) + ) __all__.append('rdv') -poolreader = Factory( name="pool reader", - description="Read data from the data pool.", - category="flow control", - nodemodule="openalea.core.system.systemnodes", - nodeclass="PoolReader", - inputs = (dict(name='Key', interface=IStr),), - outputs = (dict(name='Obj', interface=None),), - lazy = False, - - ) - +poolreader = Fa(uid="3b4eb8e24e7d11e6bff6d4bed973e64a", + name="pool reader", + description="Read data from the data pool.", + category="flow control", + nodemodule="openalea.core.system.systemnodes", + nodeclass="PoolReader", + inputs=(dict(name='Key', interface=IStr),), + outputs=(dict(name='Obj', interface=None),), + lazy=False, + + ) + __all__.append('poolreader') -poolwriter = Factory(name="pool writer", - description="Write data to the data pool.", - category="flow control", - nodemodule="openalea.core.system.systemnodes", - nodeclass="PoolWriter", - inputs = (dict(name='Key', interface=IStr), - dict(name='Obj', interface=None),), - outputs = (dict(name='Obj', interface=None),), - lazy = False, - ) +poolwriter = Fa(uid="3b4eb8e34e7d11e6bff6d4bed973e64a", + name="pool writer", + description="Write data to the data pool.", + category="flow control", + nodemodule="openalea.core.system.systemnodes", + nodeclass="PoolWriter", + inputs=(dict(name='Key', interface=IStr), + dict(name='Obj', interface=None),), + outputs=(dict(name='Obj', interface=None),), + lazy=False, + ) __all__.append('poolwriter') -pool_rw = Factory(name="pool setdefault", +pool_rw = Fa(uid="3b4eb8e44e7d11e6bff6d4bed973e64a", + name="pool setdefault", description="pool.setdefault(key,value).", category="flow control", nodemodule="openalea.core.system.systemnodes", nodeclass="PoolDefault", - inputs = (dict(name='Key', interface=IStr), - dict(name='Value', interface=None),), - outputs = (dict(name='Obj', interface=None),), - lazy = False, + inputs=(dict(name='Key', interface=IStr), + dict(name='Value', interface=None),), + outputs=(dict(name='Obj', interface=None),), + lazy=False, ) __all__.append('pool_rw') +init = Fa(uid="3b4eb8e54e7d11e6bff6d4bed973e64a", + name="init", + description="Value selector for graph initialisation", + category="flow control", + nodemodule="openalea.core.system.systemnodes", + nodeclass="InitNode", + inputs=(dict(name="val_init", interface=None, value=0.), + dict(name="value", interface=None, value=None), + dict(name="state", interface=IBool, value=True), + ), + outputs=(dict(name="value", interface=None),), -# nf = Factory(name="list accumulator", -# description="List accumulator", -# category="System", -# nodemodule="openalea.core.system.systemnodes", -# nodeclass="AccuList", -# inputs = (dict(name="value", interface=None, value=None), -# dict(name="varname", interface=IStr, value=None), -# ), -# outputs = ( dict(name="list", interface=ISequence), ), - -# ) - -# package.add_factory(nf) - - -# nf = Factory(name="float accumulator", -# description="Float accumulator", -# category="System", -# nodemodule="openalea.core.system.systemnodes", -# nodeclass="AccuFloat", -# inputs = (dict(name="value", interface=IFloat, value=0.), -# dict(name="varname", interface=IStr, value=None), -# ), -# outputs = ( dict(name="float", interface=IFloat), ), - -# ) - -# package.add_factory(nf) - - -init = Factory(name="init", - description="Value selector for graph initialisation", - category="flow control", - nodemodule="openalea.core.system.systemnodes", - nodeclass="InitNode", - inputs = (dict(name="val_init", interface=None, value=0.), - dict(name="value", interface=None, value=None), - dict(name="state", interface=IBool, value=True), - ), - outputs = ( dict(name="value", interface=None), ), - - ) + ) __all__.append('init') - - -X = Factory(name="X", - description="Function variable", - category="flow control", - nodemodule="openalea.core.system.systemnodes", - nodeclass="LambdaVar", - inputs = (dict(name="name", interface=IStr, value='x'), ), - outputs = ( dict(name="lambda", interface=None), ), - ) + +X = Fa(uid="3b4eb8e64e7d11e6bff6d4bed973e64a", + name="X", + description="Function variable", + category="flow control", + nodemodule="openalea.core.system.systemnodes", + nodeclass="LambdaVar", + inputs=(dict(name="name", interface=IStr, value='x'),), + outputs=(dict(name="lambda", interface=None),), + ) __all__.append('X') - -whileuni = Factory(name="while univariate", - description="While Loop (Univariate)", - category="flow control", - nodemodule="openalea.core.system.systemnodes", - nodeclass="WhileUniVar", - inputs = (dict(name="InitValue", interface=None, value=None), - dict(name="Test", interface=IFunction, value=None), - dict(name="Function", interface=IFunction, value=None), - ), - outputs = ( dict(name="Result", interface=None), ), - ) +whileuni = Fa(uid="3b4eb8e74e7d11e6bff6d4bed973e64a", + name="while univariate", + description="While Loop (Univariate)", + category="flow control", + nodemodule="openalea.core.system.systemnodes", + nodeclass="WhileUniVar", + inputs=(dict(name="InitValue", interface=None, value=None), + dict(name="Test", interface=IFunction, value=None), + dict(name="Function", interface=IFunction, value=None), + ), + outputs=(dict(name="Result", interface=None),), + ) __all__.append('whileuni') - -whilemulti = Factory(name="while multivariate", - description="While Loop (Multivariate)", - category="flow control", - nodemodule="openalea.core.system.systemnodes", - nodeclass="WhileMultiVar", - inputs = (dict(name="InitValues", interface=ISequence, value=[]), - dict(name="Test", interface=IFunction, value=None), - dict(name="Functions", interface=IFunction, value=None), - ), - outputs = ( dict(name="Results", interface=ISequence), ), - ) - +whilemulti = Fa(uid="3b4eb8e84e7d11e6bff6d4bed973e64a", + name="while multivariate", + description="While Loop (Multivariate)", + category="flow control", + nodemodule="openalea.core.system.systemnodes", + nodeclass="WhileMultiVar", + inputs=(dict(name="InitValues", interface=ISequence, value=[]), + dict(name="Test", interface=IFunction, value=None), + dict(name="Functions", interface=IFunction, value=None), + ), + outputs=(dict(name="Results", interface=ISequence),), + ) __all__.append('whilemulti') -whilemulti2 = Factory(name="while multivariate2", - description="While Loop (Multivariate)", - category="flow control", - nodemodule="openalea.core.system.systemnodes", - nodeclass="while_multi2", - inputs = (dict(name="InitValues", interface=ISequence, value=[]), - dict(name="Test", interface=IFunction, value=None), - dict(name="Functions", interface=IFunction, value=None), - ), - outputs = ( dict(name="Results", interface=ISequence), ), - ) - +whilemulti2 = Fa(uid="3b4eb8e94e7d11e6bff6d4bed973e64a", + name="while multivariate2", + description="While Loop (Multivariate)", + category="flow control", + nodemodule="openalea.core.system.systemnodes", + nodeclass="while_multi2", + inputs=(dict(name="InitValues", interface=ISequence, value=[]), + dict(name="Test", interface=IFunction, value=None), + dict(name="Functions", interface=IFunction, + value=None), + ), + outputs=(dict(name="Results", interface=ISequence),), + ) __all__.append('whilemulti2') -cmd = Factory(name=protected("command"), - description="Call a system command", - category="System", - nodemodule="openalea.core.system.systemnodes", - nodeclass="system_cmd", - inputs = (dict(name="commands", interface=ISequence, value=[], - desc='List of command strings'), - ), - outputs = ( dict(name="stdout", interface=None, desc='result'), - dict(name="stderr", interface=None, desc='result'), ), - ) - - +cmd = Fa(uid="3b4eb8ea4e7d11e6bff6d4bed973e64a", + name=protected("command"), + description="Call a system command", + category="System", + nodemodule="openalea.core.system.systemnodes", + nodeclass="system_cmd", + inputs=(dict(name="commands", interface=ISequence, value=[], + desc='List of command strings'), + ), + outputs=(dict(name="stdout", interface=None, desc='result'), + dict(name="stderr", interface=None, desc='result'),), + ) __all__.append('cmd') -_delay = Factory(name="delay", - description="Delay return the previous or an init value.", - category="flow control", - nodemodule="openalea.core.system.systemnodes", - nodeclass="Delay", - inputs = (dict(name="init", interface=None), - dict(name="x", interface=None), - dict(name="reset", interface=IBool )), - outputs = ( dict(name="previous", interface=None), ), - lazy = False, - ) +_delay = Fa(uid="3b4eb8eb4e7d11e6bff6d4bed973e64a", + name="delay", + description="Delay return the previous or an init value.", + category="flow control", + nodemodule="openalea.core.system.systemnodes", + nodeclass="Delay", + inputs=(dict(name="init", interface=None), + dict(name="x", interface=None), + dict(name="reset", interface=IBool)), + outputs=(dict(name="previous", interface=None),), + lazy=False, + ) __all__.append('_delay') - -_for = Factory(name="for", - description="for Loop (Univariate)", - category="flow control", - nodemodule="openalea.core.system.systemnodes", - nodeclass="For", - inputs = (dict(name="InitValue", interface=None, value=None), - dict(name="list", interface=ISequence, value=None), - dict(name="Function", interface=IFunction, value=None), - ), - outputs = ( dict(name="Result", interface=None), ), - ) +_for = Fa(uid="3c43d57e4e7d11e6bff6d4bed973e64a", + name="for", + description="for Loop (Univariate)", + category="flow control", + nodemodule="openalea.core.system.systemnodes", + nodeclass="For", + inputs=(dict(name="InitValue", interface=None, value=None), + dict(name="list", interface=ISequence, value=None), + dict(name="Function", interface=IFunction, value=None), + ), + outputs=(dict(name="Result", interface=None),), + ) __all__.append('_for') -