Salome HOME
py2yacs fixes.
[modules/yacs.git] / src / py2yacs / py2yacs.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 *-
3 # Copyright (C) 2007-2016  CEA/DEN, EDF R&D, OPEN CASCADE
4 #
5 # Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
6 # CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
7 #
8 # This library is free software; you can redistribute it and/or
9 # modify it under the terms of the GNU Lesser General Public
10 # License as published by the Free Software Foundation; either
11 # version 2.1 of the License, or (at your option) any later version.
12 #
13 # This library is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 # Lesser General Public License for more details.
17 #
18 # You should have received a copy of the GNU Lesser General Public
19 # License along with this library; if not, write to the Free Software
20 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
21 #
22 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 #
24 import ast
25
26 class FunctionProperties:
27   def __init__(self, function_name):
28     self.name = function_name
29     self.inputs=[]
30     self.outputs=None
31     self.errors=[]
32     self.imports=[]
33     pass
34   def __str__(self):
35     result = "Function:" + self.name + "\n"
36     result+= "  Inputs:" + str(self.inputs) + "\n"
37     result+= "  Outputs:"+ str(self.outputs) + "\n"
38     result+= "  Errors:" + str(self.errors) + "\n"
39     result+= "  Imports:"+ str(self.imports) + "\n"
40     return result
41
42 class v(ast.NodeVisitor):
43   def visit_Module(self, node):
44     accepted_tokens = ["Import", "ImportFrom", "FunctionDef", "ClassDef"]
45     self.global_errors=[]
46     for e in node.body:
47       type_name = type(e).__name__
48       if type_name not in accepted_tokens:
49         error="py2yacs error at line %s: not accepted statement '%s'." % (
50                e.lineno, type_name)
51         self.global_errors.append(error)
52     self.functions=[]
53     self.lastfn=""
54     self.infunc=False
55     self.inargs=False
56     self.generic_visit(node)
57     pass
58   def visit_FunctionDef(self, node):
59     if not self.infunc:
60       self.lastfn = FunctionProperties(node.name)
61       self.functions.append(self.lastfn)
62       self.infunc=True
63       #
64       self.generic_visit(node)
65       #
66       self.lastfn = None
67       self.infunc=False
68     pass
69   def visit_arg(self, node):
70     self.lastfn.inputs.append(node.arg)
71     pass
72   def visit_Return(self, node):
73     if self.lastfn.outputs is not None :
74       error="py2yacs error at line %s: multiple returns." % node.lineno
75       self.lastfn.errors.append(error)
76       return
77     self.lastfn.outputs = []
78     if node.value is None :
79       pass
80     elif 'Tuple' == type(node.value).__name__ :
81       for e in node.value.elts:
82         if 'Name' == type(e).__name__ :
83           self.lastfn.outputs.append(e.id)
84         else :
85           error="py2yacs error at line %s: invalid type returned '%s'." % (
86                   node.lineno, type(e).__name__)
87           self.lastfn.errors.append(error)
88     else:
89       if 'Name' == type(node.value).__name__ :
90         self.lastfn.outputs.append(node.value.id)
91       else :
92         error="py2yacs error at line %s: invalid type returned '%s'." %(
93                   node.lineno, type(node.value).__name__)
94         self.lastfn.errors.append(error)
95         pass
96       pass
97     pass
98
99   def visit_ClassDef(self, node):
100     # just ignore classes
101     pass
102
103   def visit_Import(self, node):
104     if self.infunc:
105       for n in node.names:
106         self.lastfn.imports.append(n.name)
107   def visit_ImportFrom(self, node):
108     if self.infunc:
109       m=node.module
110       for n in node.names:
111         self.lastfn.imports.append(m+"."+n.name)
112
113 class vtest(ast.NodeVisitor):
114   def generic_visit(self, node):
115     ast.NodeVisitor.generic_visit(self, node)
116
117 def create_yacs_schema(text, fn_name, fn_args, fn_returns, file_name):
118   import pilot
119   import SALOMERuntime
120   SALOMERuntime.RuntimeSALOME_setRuntime()
121   runtime = pilot.getRuntime()
122   schema = runtime.createProc("schema")
123   node = runtime.createScriptNode("", "default_name")
124   schema.edAddChild(node)
125   fncall = "\n%s=%s(%s)\n"%(",".join(fn_returns),
126                             fn_name,
127                             ",".join(fn_args))
128   node.setScript(text+fncall)
129   td=schema.getTypeCode("double")
130   for p in fn_args:
131     newport = node.edAddInputPort(p, td)
132     newport.edInit(0.0)
133   for p in fn_returns:
134     node.edAddOutputPort(p, td)
135   myContainer=schema.createContainer("Py2YacsContainer")
136   node.setExecutionMode(pilot.InlineNode.REMOTE_STR)
137   node.setContainer(myContainer)
138   schema.saveSchema(file_name)
139
140 def get_properties(text_file):
141   bt=ast.parse(text_file)
142   w=v()
143   w.visit(bt)
144   return w.functions, w.global_errors
145
146 def main(python_path, yacs_path, function_name="_exec"):
147   with open(python_path, 'r') as f:
148     text_file = f.read()
149   fn_name = function_name
150   functions,errors = get_properties(text_file)
151   error_string = ""
152   if len(errors) > 0:
153     error_string += "global errors:\n"
154     error_string += '\n'.join(errors)
155     return error_string
156   fn_properties = next((f for f in functions if f.name == fn_name), None)
157   if fn_properties is not None :
158     if not fn_properties.errors :
159       create_yacs_schema(text_file, fn_name,
160                          fn_properties.inputs, fn_properties.outputs,
161                          yacs_path)
162     else:
163       error_string += '\n'.join(fn_properties.errors)
164   else:
165     error_string += "Function not found:"
166     error_string += fn_name
167   return error_string
168
169 if __name__ == '__main__':
170   import argparse
171   parser = argparse.ArgumentParser(description="Generate a YACS schema from a python file containing a function to run.")
172   parser.add_argument("file", help='Path to the python file')
173   parser.add_argument("-o","--output",
174         help='Path to the output file (yacs_schema.xml by default)',
175         default='yacs_schema.xml')
176   parser.add_argument("-d","--def_name",
177         help='Name of the function to call in the yacs node (_exec by default)',
178         default='_exec')
179   args = parser.parse_args()
180   erreurs = main(args.file, args.output, args.def_name)
181   import sys
182   if len(erreurs) > 0:
183     print(erreurs)
184     sys.exit(1)
185   else:
186     sys.exit(0)