3 # Copyright (C) 2007-2024 CEA, EDF
5 # This library is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU Lesser General Public
7 # License as published by the Free Software Foundation; either
8 # version 2.1 of the License, or (at your option) any later version.
10 # This library is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 # Lesser General Public License for more details.
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with this library; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 class FunctionProperties:
24 def __init__(self, function_name):
25 self.name = function_name
32 result = "Function:" + self.name + "\n"
33 result+= " Inputs:" + str(self.inputs) + "\n"
34 result+= " Outputs:"+ str(self.outputs) + "\n"
35 result+= " Errors:" + str(self.errors) + "\n"
36 result+= " Imports:"+ str(self.imports) + "\n"
39 class VisitAST(ast.NodeVisitor):
40 def visit_Module(self, node):
41 accepted_tokens = ["Import", "ImportFrom", "FunctionDef", "ClassDef", "If"]
44 type_name = type(e).__name__
45 if type_name not in accepted_tokens:
46 error="py2yacs error at line %s: not accepted statement '%s'." % (
48 self.global_errors.append(error)
53 self.generic_visit(node)
55 def visit_FunctionDef(self, node):
57 self.lastfn = FunctionProperties(node.name)
58 self.functions.append(self.lastfn)
61 self.generic_visit(node)
66 def visit_arg(self, node):
67 self.lastfn.inputs.append(node.arg)
69 def visit_Return(self, node):
70 if self.lastfn.outputs is not None :
71 error="py2yacs error at line %s: multiple returns." % node.lineno
72 self.lastfn.errors.append(error)
74 self.lastfn.outputs = []
75 if node.value is None :
77 elif 'Tuple' == type(node.value).__name__ :
78 for e in node.value.elts:
79 if 'Name' == type(e).__name__ :
80 self.lastfn.outputs.append(e.id)
82 error="py2yacs error at line %s: invalid type returned '%s'." % (
83 node.lineno, type(e).__name__)
84 self.lastfn.errors.append(error)
86 if 'Name' == type(node.value).__name__ :
87 self.lastfn.outputs.append(node.value.id)
89 error="py2yacs error at line %s: invalid type returned '%s'." %(
90 node.lineno, type(node.value).__name__)
91 self.lastfn.errors.append(error)
96 def visit_ClassDef(self, node):
100 def visit_Import(self, node):
103 self.lastfn.imports.append(n.name)
104 def visit_ImportFrom(self, node):
108 self.lastfn.imports.append(m+"."+n.name)
110 class vtest(ast.NodeVisitor):
111 def generic_visit(self, node):
112 ast.NodeVisitor.generic_visit(self, node)
114 def create_yacs_schema(text, fn_name, fn_args, fn_returns, file_name):
117 SALOMERuntime.RuntimeSALOME_setRuntime()
118 runtime = pilot.getRuntime()
119 schema = runtime.createProc("schema")
120 node = runtime.createScriptNode("", "default_name")
121 schema.edAddChild(node)
122 fncall = "\n%s=%s(%s)\n"%(",".join(fn_returns),
125 node.setScript(text+fncall)
126 td=schema.getTypeCode("double")
128 newport = node.edAddInputPort(p, td)
131 node.edAddOutputPort(p, td)
132 myContainer=schema.createContainer("Py2YacsContainer")
133 node.setExecutionMode(pilot.InlineNode.REMOTE_STR)
134 node.setContainer(myContainer)
135 schema.saveSchema(file_name)
137 def get_properties(text_file):
139 bt=ast.parse(text_file)
140 except SyntaxError as err:
142 return [], ["".join(traceback.format_exception_only(SyntaxError,err))]
145 return w.functions, w.global_errors
147 def function_properties(python_path, fn_name):
149 python_path : path to a python file
150 fn_name : name of a function in the file
151 return : properties of the function. see class FunctionProperties
153 with open(python_path, 'r') as f:
155 functions,errors = get_properties(text_file)
156 result = [fn for fn in functions if fn.name == fn_name]
158 raise Exception("Function not found: {}".format(fn_name))
162 error_string += "Global errors in file {}\n".format(python_path)
163 error_string += '\n'.join(errors)
164 raise Exception(error_string)
165 if len(result.errors) > 0:
166 error_string += "Errors when parsing function {}\n".format(fn_name)
167 error_string += '\n'.join(result.errors)
168 raise Exception(error_string)
172 def main(python_path, yacs_path, function_name="_exec"):
173 with open(python_path, 'r') as f:
175 fn_name = function_name
176 functions,errors = get_properties(text_file)
179 error_string += "global errors:\n"
180 error_string += '\n'.join(errors)
182 fn_properties = next((f for f in functions if f.name == fn_name), None)
183 if fn_properties is not None :
184 if not fn_properties.errors :
185 create_yacs_schema(text_file, fn_name,
186 fn_properties.inputs, fn_properties.outputs,
189 error_string += '\n'.join(fn_properties.errors)
191 error_string += "Function not found:"
192 error_string += fn_name
195 if __name__ == '__main__':
197 parser = argparse.ArgumentParser(description="Generate a YACS schema from a python file containing a function to run.")
198 parser.add_argument("file", help='Path to the python file')
199 parser.add_argument("-o","--output",
200 help='Path to the output file (yacs_schema.xml by default)',
201 default='yacs_schema.xml')
202 parser.add_argument("-d","--def_name",
203 help='Name of the function to call in the yacs node (_exec by default)',
205 args = parser.parse_args()
206 erreurs = main(args.file, args.output, args.def_name)