From 5aefd45c2e6a2859572408def6f420ed85b7e5c1 Mon Sep 17 00:00:00 2001
From: Jonathan Lambrechts <jonathan.lambrechts@uclouvain.be>
Date: Thu, 23 Nov 2017 22:38:33 +0100
Subject: [PATCH] python api

---
 api/GenApi.py | 574 +++++++++++++++++++++++++++-----------------------
 api/Makefile  |   4 +-
 api/gen.py    |   1 +
 api/test.py   |  48 +++++
 4 files changed, 366 insertions(+), 261 deletions(-)
 create mode 100644 api/test.py

diff --git a/api/GenApi.py b/api/GenApi.py
index 27e4731222..72b623fe1f 100644
--- a/api/GenApi.py
+++ b/api/GenApi.py
@@ -1,249 +1,185 @@
 class arg:
 
-    def __init__(self, name, value=None):
+    def __init__(self,name,value,type_cpp,type_c,out):
         self.name = name
         self.value = value
+        self.out = out
+        self.type_cpp = type_cpp
+        self.type_c = type_c
+        self.cpp_value = (" = "+value) if value else ""
 
-    @property
-    def cpp_value(self):
-        if self.value is None:
-            return ""
-        return " = "+self.value
-
-    @property
-    def cpp(self):
         n = self.type_cpp 
         if n[-1] != "&":
             n += " "
         n += self.name
         n += self.cpp_value
-        return n
-
-    @property
-    def c_cpp_arg(self):
-        return self.name
-
-    @property
-    def c_cpp_pre(self):
-        return ""
-    @property
-    def c_cpp_post(self):
-        return ""
-    @property
-    def c(self):
-        return self.type_c + " " + self.name 
-
-class simplearg(arg):
-    def __init__(self,cpptype,ctype,out,name,value):
-        self.type_cpp = cpptype
-        self.type_c = ctype
-        arg.__init__(self,name,value)
-
-class iint(simplearg):
-    def __init__(self,name,value=None):
-        simplearg.__init__(self,"const int","const int",False,name,value)
+        self.cpp = n
 
-class oint(simplearg):
-    def __init__(self,name,value=None):
-        simplearg.__init__(self,"int &","int*",True,name,value)
-    rtype_cpp = "int"
-    rtype_c = "int"
-    @property
-    def c_cpp_arg(self):
-        return "*"+self.name
+        self.c_arg = self.name
+        self.c_pre = ""
+        self.c_post = ""
+        self.c = type_c + " " + name
 
-class istring(simplearg):
-    def __init__(self,name,value=None):
-        simplearg.__init__(self,"const std::string &", "const char*",False,name,value)
-    @property
-    def cpp_value(self):
-        if self.value is None:
-            return ""
-        return " = \""+self.value+"\""
-
-class ostring(simplearg):
-    def __init__(self,name,value=None):
-        simplearg.__init__(self,"std::string &","char**",True,name,value)
-    @property
-    def c_cpp_arg(self):
-        return "api_"+self.name+"_"
-    @property
-    def c_cpp_pre(self):
-        return "  std::string "+self.c_cpp_arg +";\n"
-    @property
-    def c_cpp_post(self):
-        return "  *"+self.name+" = strdup("+self.c_cpp_arg+".c_str());\n"
-
-class idouble(simplearg):
-    def __init__(self,name,value=None):
-        simplearg.__init__(self,"const double","const double",False,name,value)
+        self.python_arg = "not_implemented"
+        self.python_return = "not_implemented"
+        self.python_pre = ""
 
-class odouble(simplearg):
-    def __init__(self,name,value=None):
-        simplearg.__init__(self,"double &","double*",True,name,value)
-    @property
-    def c_cpp_arg(self):
-        return "*"+self.name
+def iint(name,value=None):
+    a = arg(name,value,"const int","const int",False)
+    a.python_arg = "c_int("+name+")"
+    return a
 
-class ovectorpair(arg):
-    def __init__(self,name,value=None):
-        arg.__init__(self,name,value)
-    type_cpp = "vector_pair &"
-    type_c = "int**"
-    @property
-    def c_cpp_arg(self):
-        return "api_"+self.name+"_"
-    @property
-    def c_cpp_pre(self):
-        return "  vector_pair "+self.c_cpp_arg +";\n"
-    @property
-    def c_cpp_post(self):
-        return "  pairvector2intptr("+self.c_cpp_arg+", " + self.name + ", "+self.name+"Size);\n"
-    @property
-    def c (self):
-        return "int** "+self.name+", size_t* "+self.name+"Size"
-
-class ivectorpair(arg):
-    def __init__(self,name,value=None):
-        arg.__init__(self,name,value)
-    type_cpp = "const vector_pair &"
-    type_c = "const int*"
-    @property
-    def c_cpp_arg(self):
-        return "intptr2pairvector("+self.name+","+self.name+"Size)"
-    @property
-    def c (self):
-        return "int* "+self.name+", size_t "+self.name+"Size"
-
-
-class ibool(arg):
+class oint(arg):
+    rtype_cpp = "int"
+    rtype_c = "int"
     def __init__(self,name,value=None):
-        arg.__init__(self,name,value)
-    type_cpp = "const bool"
-    type_c = "const int"
+        arg.__init__(self,name,value,"int&","int*",True)
+        self.c_arg = "*"+name
+
+def istring(name,value=None):
+    value = "\""+value+"\"" if value is not None else None
+    a = arg(name,value,"const std::string&","const char*",False)
+    a.python_arg = "c_char_p("+name+".encode())"
+    return a
+
+def ostring(name,value=None):
+    a = arg(name,value,"std::string &","char**",True)
+    a.c_arg = "api_"+name+"_"
+    a.c_pre = "  std::string "+a.c_arg +";\n"
+    a.c_post = "  *"+name+" = strdup("+a.c_arg+".c_str());\n"
+    name_ = "api_"+name+"_"
+    a.python_pre = name_+" = c_char_p()"
+    a.python_arg = "byref("+name_+")"
+    a.python_return = "_ostring("+name_+")"
+    return a
+
+def idouble(name,value=None):
+     a = arg(name,value,"const double","const double",False)
+     a.python_arg = "c_double("+name+")"
+     return a
+
+def odouble(name,value=None):
+    a = arg(name,value,"double&","double*",True)
+    a.c_arg = "*"+name
+    name_ = "api_"+name+"_"
+    a.python_pre = name_+" = c_double()"
+    a.python_arg = "byref("+name_+")"
+    a.python_return = name_+".value"
+    return a
+
+def ovectorpair(name,value=None):
+    a = arg(name,value,"vector_pair &","int**",True)
+    name_ = "api_"+name+"_"
+    name_n = name_ + "n_"
+    a.c_arg = name_
+    a.c_pre = "  vector_pair "+name_ +";\n"
+    a.c_post = "  pairvector2intptr("+name_+"," + name + ","+name_n+");\n"
+    a.c = "int** "+name+",size_t* "+name_n
+    a.python_pre = name_+", "+name_n+" = POINTER(c_int)(), c_size_t()"
+    a.python_arg = "byref("+name_+"),byref("+name_n+")"
+    a.python_return = "_ovectorpair("+name_+","+name_n+".value)"
+    return a
+
+def ivectorpair(name,value=None):
+    a = arg(name,value,"const vector_pair &","const int*",False)
+    a.c_arg = "intptr2pairvector("+name+","+name+"_n)"
+    a.c = "int* "+name+",size_t "+name+"_n"
+    a.python_pre = "api_"+name+"_, api"+name+"_n_ = _ivectorpair("+name+")"
+    a.python_arg = "api_"+name+"_, api"+name+"_n_"
+    return a
+
+def ibool(name,value=None):
+    a = arg(name,value,"const bool","const int",False)
+    a.python_arg = "c_int(bool("+name+"))"
+    return a
     
-class obool(arg):
-    def __init__(self,name,value=None):
-        arg.__init__(self,name,value)
-    type_cpp = "bool &"
-    type_c = "int*"
-    @property
-    def c_cpp_arg(self):
-        return "api_"+self.name+"_"
-    @property
-    def c_cpp_pre(self):
-        return "  bool "+self.c_cpp_arg +";\n"
-    @property
-    def c_cpp_post(self):
-        return "  *"+self.name+" = (int)"+self.c_cpp_arg+";\n"
-
-class ivectorint(arg):
-    def __init__(self,name,value=None):
-        arg.__init__(self,name,value)
-    type_cpp = "const std::vector<int> &"
-    type_c = "const int*"
-    @property
-    def c_cpp_arg(self):
-        return "ptr2vector("+self.name+", "+self.name+"Size)"
-    @property
-    def c (self):
-        return "int* "+self.name+", size_t "+self.name+"Size"
-
-class ovectorint(arg):
-    def __init__(self,name,value=None):
-        arg.__init__(self,name,value)
-    type_cpp = "std::vector<int> &"
-    type_c = "int**"
-    @property
-    def c_cpp_arg(self):
-        return "api_"+self.name+"_"
-    @property
-    def c_cpp_pre(self):
-        return "  std::vector<int> "+self.c_cpp_arg +";\n"
-    @property
-    def c_cpp_post(self):
-        return "  vector2ptr("+self.c_cpp_arg+", " + self.name + ", "+self.name+"Size);\n"
-    @property
-    def c (self):
-        return "int** "+self.name+", size_t* "+self.name+"Size"
-
-
-class ovectorvectorint(arg):
-    def __init__(self,name,value=None):
-        arg.__init__(self,name,value)
-    type_cpp = "std::vector<std::vector<int> > &"
-    type_c = "int**"
-    @property
-    def c_cpp_arg(self):
-        return "api_"+self.name+"_"
-    @property
-    def c_cpp_pre(self):
-        return "  std::vector<std::vector<int> > "+self.c_cpp_arg +";\n"
-    @property
-    def c_cpp_post(self):
-        return "  vectorvector2ptrptr("+self.c_cpp_arg+", " + self.name + ", "+self.name+"Size, "+self.name+"SizeSize);\n"
-    @property
-    def c (self):
-        return "int*** "+self.name+", size_t** "+self.name+"Size"+", size_t *"+self.name+"SizeSize"
-
-class ovectorvectorpair(arg):
-    def __init__(self,name,value=None):
-        arg.__init__(self,name,value)
-    type_cpp = "std::vector<vector_pair> &"
-    type_c = "int**"
-    @property
-    def c_cpp_arg(self):
-        return "api_"+self.name+"_"
-    @property
-    def c_cpp_pre(self):
-        return "  std::vector<vector_pair >"+self.c_cpp_arg +";\n"
-    @property
-    def c_cpp_post(self):
-        return "  pairvectorvector2intptrptr("+self.c_cpp_arg+", " + self.name + ", "+self.name+"Size, "+self.name+"SizeSize);\n"
-    @property
-    def c (self):
-        return "int*** "+self.name+", size_t** "+self.name+"Size"+", size_t *"+self.name+"SizeSize"
-
-class ivectordouble(arg):
-    def __init__(self,name,value=None):
-        arg.__init__(self,name,value)
-    type_cpp = "const std::vector<double> &"
-    type_c = "double**"
-    @property
-    def c_cpp_arg(self):
-        return "ptr2vector("+self.name+", "+self.name+"Size)"
-    @property
-    def c (self):
-        return "double* "+self.name+", size_t "+self.name+"Size"
-
-class ovectordouble(arg):
-    def __init__(self,name,value=None):
-        arg.__init__(self,name,value)
-    type_cpp = "std::vector<double> &"
-    type_c = "double*"
-    @property
-    def c_cpp_arg(self):
-        return "api_"+self.name+"_"
-    @property
-    def c_cpp_pre(self):
-        return "  std::vector<double> "+self.c_cpp_arg +";\n"
-    @property
-    def c_cpp_post(self):
-        return "  vector2ptr("+self.c_cpp_arg+", " + self.name + ", "+self.name+"Size);\n"
-    @property
-    def c (self):
-        return "double** "+self.name+", size_t* "+self.name+"Size"
+def obool(name,value=None):
+    a = arg(name,value,"bool &","int*",True)
+    a.c_arg = "api_"+name+"_"
+    a.c_pre = "  bool "+a.c_arg +";\n"
+    a.c_post = "  *"+name+" = (int)"+a.c_arg+";\n"
+    return a
+
+def ivectorint(name,value=None):
+    a = arg(name,value,"const std::vector<int> &","const int*",False)
+    a.c_arg = "ptr2vector("+name+","+name+"_n)"
+    a.c = "int* "+name+",size_t "+name+"_n"
+    a.python_pre = "api_"+name+"_, api"+name+"_n_ = _ivectorint("+name+")"
+    a.python_arg = "api_"+name+"_, api"+name+"_n_"
+    return a
+
+def ovectorint(name,value=None):
+    a = arg(name,value,"std::vector<int> &","int**",True)
+    name_ = "api_"+name+"_"
+    name_n = name_ + "n_"
+    a.c_arg = name_
+    a.c_pre = "  std::vector<int> "+name_ +";\n"
+    a.c_post = "  vector2ptr("+name_+"," + name + ","+name_n+");\n"
+    a.c = "int** "+name+",size_t* "+name_n
+    a.python_pre = name_+", "+name_n+" = POINTER(c_int)(), c_size_t()"
+    a.python_arg = "byref("+name_+"),byref("+name_n+")"
+    a.python_return = "_ovectorint("+name_+","+name_n+".value)"
+    return a
+
+def ivectordouble(name,value=None):
+    a = arg(name,value,"const std::vector<double> &","double**",False)
+    a.c_arg = "ptr2vector("+name+","+name+"_n)"
+    a.c  = "double* "+name+",size_t "+name+"_n"
+    a.python_pre = "api_"+name+"_, api"+name+"_n_ = _ivectordouble("+name+")"
+    a.python_arg = "api_"+name+"_, api"+name+"_n_"
+    return a
+
+def ovectordouble(name,value=None):
+    a = arg(name,value,"std::vector<double> &","double*",True)
+    name_ = "api_"+name+"_"
+    name_n = name_ + "n_"
+    a.c_arg = name_
+    a.c_pre = "  std::vector<double> "+a.c_arg +";\n"
+    a.c_post = "  vector2ptr("+name_+"," + name + ","+name_n+";\n"
+    a.c  = "double** "+name+",size_t* "+name+"_n"
+    a.python_pre = name_+", "+name_n+" = POINTER(c_double)(), c_size_t()"
+    a.python_arg = "byref("+name_+"),byref("+name_n+")"
+    a.python_return = "_ovectordouble("+name_+","+name_n+".value)"
+    return a
+
+def ovectorvectorint(name,value=None):
+    a = arg(name,value,"std::vector<std::vector<int> > &","int**",True)
+    name_ = "api_"+name+"_"
+    name_n = name_ + "n_"
+    name_nn = name_ + "nn_"
+    a.c_arg = name_
+    a.c_pre = "  std::vector<std::vector<int> > "+a.c_arg +";\n"
+    a.c_post = "  vectorvector2ptrptr("+name_+"," + name + ","+name_n+","+name_nn+");\n"
+    a.c  = "int*** "+name+",size_t** "+name_n+",size_t *"+name_nn
+    a.python_pre = name_+", "+name_n+", "+name_nn +" = POINTER(POINTER(c_int))(), POINTER(c_size_t)(), c_size_t()"
+    a.python_arg = "byref("+name_+"),byref("+name_n+"),byref("+name_nn+")"
+    a.python_return = "_ovectorvectorint("+name_+","+name_n+","+name_nn+")"
+    return a
+
+def ovectorvectorpair(name,value=None):
+    a = arg(name,value,"std::vector<vector_pair> &","int**",True)
+    name_ = "api_"+name+"_"
+    name_n = name_ + "n_"
+    name_nn = name_ + "nn_"
+    a.c_arg = name_
+    a.c_pre = "  std::vector<vector_pair >"+name_ +";\n"
+    a.c_post = "  pairvectorvector2intptrptr("+name_+"," + name + ","+name_n+","+name_nn+";\n"
+    a.c  = "int*** "+name+",size_t** "+name_n+",size_t *"+name_nn
+    a.python_pre = name_+", "+name_n+", "+name_nn +" = POINTER(POINTER(c_int))(), POINTER(c_size_t)(), c_size_t()"
+    a.python_arg = "byref("+name_+"),byref("+name_n+"),byref("+name_nn+")"
+    a.python_return = "_ovectorvectorpair("+name_+","+name_n+","+name_nn+")"
+    return a
 
 class Module:
 
-    def __init__(self, name):
+    def __init__(self,name):
         self.name = name
         self.fs = []
 
-    def add(self,rtype, name, *args):
+    def add(self,rtype,name,*args):
         self.fs.append((rtype,name,args))
 
-cpp_header="""// Gmsh - Copyright (C) 1997-2017 C. Geuzaine, J.-F. Remacle
+cpp_header="""// Gmsh - Copyright (C) 1997-2017 C. Geuzaine,J.-F. Remacle
 //
 // See the LICENSE.txt file for license information. Please report all
 // bugs and problems to the public mailing list <gmsh@onelab.info>.
@@ -253,18 +189,18 @@ cpp_header="""// Gmsh - Copyright (C) 1997-2017 C. Geuzaine, J.-F. Remacle
 
 // This is the embryo of what will become the Gmsh API.
 //
-// Don't use it yet, it's not ready:-) We plan to release a first version in
-// Gmsh 3.1, and something more complete in Gmsh 4.0.
+// Don't use it yet,it's not ready:-) We plan to release a first version in
+// Gmsh 3.1,and something more complete in Gmsh 4.0.
 //
 // Your input is welcome: please contribute your ideas on
 // https://gitlab.onelab.info/gmsh/gmsh/issues/188
 //
-// By design, the API is purely functional, and only uses elementary C++ types
+// By design,the API is purely functional,and only uses elementary C++ types
 // from the standard library. This design should not and will not change.
 
 // All functions return 0 as the first entry of the returned vector on
 // successful completion. Additional integer results can be appends to this
-// returned value, depending on context.
+// returned value,depending on context.
 
 #include <cmath>
 #include <vector>
@@ -276,9 +212,9 @@ cpp_header="""// Gmsh - Copyright (C) 1997-2017 C. Geuzaine, J.-F. Remacle
 #define GMSH_API
 #endif
 
-typedef std::vector<std::pair<int, int> > vector_pair;
+typedef std::vector<std::pair<int,int> > vector_pair;
 
-GMSH_API void gmshInitialize(int argc, char **argv);
+GMSH_API void gmshInitialize(int argc,char **argv);
 """
 
 cpp_footer=""" 
@@ -287,7 +223,7 @@ cpp_footer="""
 #endif
 """
 
-c_header="""// Gmsh - Copyright (C) 1997-2017 C. Geuzaine, J.-F. Remacle
+c_header="""// Gmsh - Copyright (C) 1997-2017 C. Geuzaine,J.-F. Remacle
 //
 // See the LICENSE.txt file for license information. Please report all
 // bugs and problems to the public mailing list <gmsh@onelab.info>.
@@ -297,18 +233,18 @@ c_header="""// Gmsh - Copyright (C) 1997-2017 C. Geuzaine, J.-F. Remacle
 
 // This is the embryo of what will become the Gmsh API.
 //
-// Don't use it yet, it's not ready:-) We plan to release a first version in
-// Gmsh 3.1, and something more complete in Gmsh 4.0.
+// Don't use it yet,it's not ready:-) We plan to release a first version in
+// Gmsh 3.1,and something more complete in Gmsh 4.0.
 //
 // Your input is welcome: please contribute your ideas on
 // https://gitlab.onelab.info/gmsh/gmsh/issues/188
 //
-// By design, the API is purely functional, and only uses elementary C++ types
+// By design,the API is purely functional,and only uses elementary C++ types
 // from the standard library. This design should not and will not change.
 
 // All functions return 0 as the first entry of the returned vector on
 // successful completion. Additional integer results can be appends to this
-// returned value, depending on context.
+// returned value,depending on context.
 
 #if defined(WIN32)
 #define GMSH_API __declspec(dllexport)
@@ -318,7 +254,8 @@ c_header="""// Gmsh - Copyright (C) 1997-2017 C. Geuzaine, J.-F. Remacle
 
 #include <stdlib.h>
 
-GMSH_API void gmshcInitialize(char argc, char **argv);
+GMSH_API void gmshcInitialize(char argc,char **argv);
+GMSH_API void gmshcFree_(void *p);
 """
 
 c_footer="""
@@ -327,7 +264,7 @@ c_footer="""
 #endif
 """
 
-c_cpp_header="""// Gmsh - Copyright (C) 1997-2017 C. Geuzaine, J.-F. Remacle
+c_header="""// Gmsh - Copyright (C) 1997-2017 C. Geuzaine,J.-F. Remacle
 //
 // See the LICENSE.txt file for license information. Please report all
 // bugs and problems to the public mailing list <gmsh@onelab.info>.
@@ -339,12 +276,12 @@ extern \"C\" {
 #include <cstring>
 
 template<typename t>
-std::vector<t> ptr2vector(const t *p, size_t size) {
+std::vector<t> ptr2vector(const t *p,size_t size) {
   return std::vector<t>(p,p+size);
 }
 
 template<typename t>
-void vector2ptr(const std::vector<t>&v, t **p, size_t *size) {
+void vector2ptr(const std::vector<t>&v,t **p,size_t *size) {
   *p = (t*)malloc(sizeof(t)*(v.size()));
   for (size_t i = 0; i < v.size(); ++i){
     (*p)[i] = v[i];
@@ -352,7 +289,7 @@ void vector2ptr(const std::vector<t>&v, t **p, size_t *size) {
   *size = v.size();
 }
 
-void pairvector2intptr(const vector_pair &v, int **p, size_t *size) {
+void pairvector2intptr(const vector_pair &v,int **p,size_t *size) {
   *p = (int*)malloc(sizeof(int)*(v.size()*2));
   for (size_t i = 0; i < v.size(); ++i){
     (*p)[i*2+0] = v[i].first;
@@ -361,9 +298,9 @@ void pairvector2intptr(const vector_pair &v, int **p, size_t *size) {
   *size = v.size()*2;
 }
 
-vector_pair intptr2pairvector(const int *p, size_t size){
-  vector_pair v(size);
-  for (size_t i = 0; i < size; ++i) {
+vector_pair intptr2pairvector(const int *p,size_t size){
+  vector_pair v(size/2);
+  for (size_t i = 0; i < size/2; ++i) {
     v[i].first = p[i*2+0];
     v[i].second = p[i*2+1];
   }
@@ -371,45 +308,136 @@ vector_pair intptr2pairvector(const int *p, size_t size){
 }
 
 template<typename t>
-void vectorvector2ptrptr(const std::vector<std::vector<t> > &v, t ***p, size_t **size, size_t *sizeSize) {
+void vectorvector2ptrptr(const std::vector<std::vector<t> > &v,t ***p,size_t **size,size_t *sizeSize) {
   *p = (t**)malloc(sizeof(t*)*v.size());
   *size = (size_t*)malloc(sizeof(size_t)*v.size()); 
   for (size_t i = 0; i < v.size(); ++i)
-    vector2ptr(v[i], &((*p)[i]), &((*size)[i]));
+    vector2ptr(v[i],&((*p)[i]),&((*size)[i]));
   *sizeSize = v.size();
 }
 
-int** pairvectorvector2intptrptr(const std::vector<vector_pair > &v, int ***p, size_t **size, size_t *sizeSize) {
+int** pairvectorvector2intptrptr(const std::vector<vector_pair > &v,int ***p,size_t **size,size_t *sizeSize) {
   *p = (int**)malloc(sizeof(int*)*v.size());
   for (size_t i = 0; i < v.size(); ++i)
     pairvector2intptr(v[i],p[i],size[i]);
   *sizeSize = v.size();
 }
 
-void gmshcInitialize(char argc, char **argv){
-  gmshInitialize(argc, argv);
+void gmshcInitialize(char argc,char **argv){
+  gmshInitialize(argc,argv);
+}
+
+void gmshcFree_(void *p) {
+  if(p) free(p);
 }
 """
 
+python_header = """from ctypes import *
+import signal
+import os
+signal.signal(signal.SIGINT,signal.SIG_DFL)
+libdir = os.path.dirname(os.path.realpath(__file__))
+lib = CDLL(libdir+"/libgmshc.so")
+
+use_numpy = False
+try :
+    import numpy
+    use_numpy = True
+    try : 
+        from weakref import finalize
+    except :
+        from backports.weakref import finalize
+except :
+    pass
+
+def Initialize() :
+    lib.gmshcInitialize(c_int(0),c_voidp(None))
+
+def _ostring(s) :
+    sp = s.value.decode("utf-8")
+    lib.gmshcFree_(s)
+    return sp
+
+def _ovectorpair(ptr,size):
+    if use_numpy :
+        v = numpy.ctypeslib.as_array(ptr, (size//2,2))
+        finalize(v, lib.gmshcFree_, ptr)
+    else :
+        v = list((ptr[i*2],ptr[i*2+1]) for i in range(size//2))
+        lib.gmshcFree_(ptr)
+    return v
+
+def _ovectorint(ptr,size):
+    if use_numpy :
+        v = numpy.ctypeslib.as_array(ptr, (size,))
+        finalize(v, lib.gmshcFree_, ptr)
+    else :
+        v = list(ptr[i] for i in range(size))
+        lib.gmshcFree_(ptr)
+    return v
+
+def _ovectordouble(ptr,size):
+    if use_numpy :
+        v = numpy.ctypeslib.as_array(ptr, (size,))
+        finalize(v, lib.gmshcFree_, ptr)
+    else :
+        v = list(ptr[i] for i in range(size))
+        lib.gmshcFree_(ptr)
+    return v
+
+
+def _ovectorvectorint(ptr,size,n):
+    v = [_ovectorint(pointer(ptr[i].contents),size[i]) for i in range(n.value)]
+    lib.gmshcFree_(size)
+    lib.gmshcFree_(ptr)
+    return v
+
+def _ovectorvectorpair(ptr,size,n):
+    v = [_ovectorpair(pointer(ptr[i].contents),size[i]) for i in range(n.value)]
+    lib.gmshcFree_(size)
+    lib.gmshcFree_(ptr)
+    return v
+
+def _ivectorint(o):
+    if use_numpy :
+        return  numpy.ascontiguousarray(o,numpy.int32).ctypes, c_size_t(len(o))
+    else :
+        return byref((c_int*len(o))(*o)), c_size_t(len(o))
+        
+
+def _ivectordouble(o):
+    if use_numpy :
+        return  numpy.ascontiguousarray(o,numpy.float64).ctypes, c_size_t(len(o))
+    else :
+        return byref((c_double*len(o))(*o)), c_size_t(len(o))
+
+def _ivectorpair(o):
+    if use_numpy :
+        return  numpy.ascontiguousarray(o,numpy.int32).reshape(len(o),2).ctypes, c_size_t(len(o)*2)
+    else :
+        return byref(((c_int*2)*len(o))(*o)), c_size_t(len(o)*2)
+
+"""
+
 class API:
 
     def __init__(self):
         self.modules = []
 
-    def add_module(self, name):
+    def add_module(self,name):
         module = Module(name)
         self.modules.append(module)
         return module
 
-    def write_cpp(self, filename):
+    def write_cpp(self,filename):
         with open(filename+".h","w") as f:
             f.write(cpp_header)
             for module in self.modules:
                 f.write("\n")
                 f.write("// gmsh"+module.name+"\n")
-                for rtype, name, args in module.fs:
+                for rtype,name,args in module.fs:
                     rt = rtype.rtype_cpp if rtype else "void"
-                    f.write("GMSH_API " + rt + " gmsh" + module.name+name+"("+", ".join(
+                    f.write("GMSH_API " + rt + " gmsh" + module.name+name+"("+",".join(
                         list((a.cpp for a in args)))+");\n")
             f.write(cpp_footer)
 
@@ -419,35 +447,63 @@ class API:
             for module in self.modules:
                 f.write("\n")
                 f.write("/* gmsh"+module.name+" */\n")
-                for rtype, name, args in module.fs:
+                for rtype,name,args in module.fs:
                     f.write("GMSH_API "+(rtype.rtype_c if rtype else "void"))
                     f.write(" gmshc" + module.name+name+"("
-                            +", ".join(list((a.c for a in args+(oint("ierr"),))))
+                            +",".join(list((a.c for a in args+(oint("ierr"),))))
                             + ");\n")
             f.write(c_footer)
 
         with open(filename+".cc","w") as f:
-            f.write(c_cpp_header)
+            f.write(c_header)
             for module in self.modules:
                 f.write("\n")
                 f.write("/* gmsh"+module.name+" */\n")
-                for rtype, name, args in module.fs:
+                for rtype,name,args in module.fs:
                     f.write(rtype.rtype_c if rtype else "void")
                     f.write(" gmshc" + module.name+name+"("
-                        +", ".join(list((a.c for a in args+(oint("ierr"),))))+"){\n")
+                        +",".join(list((a.c for a in args+(oint("ierr"),))))+"){\n")
                     if rtype:
                         f.write("  "+ rtype.rtype_c + " result_api_;\n")
                     f.write("  if(ierr) *ierr = 0;\n");
                     f.write("  try {\n");
-                    f.write("".join((a.c_cpp_pre for a in args)))
+                    f.write("".join((a.c_pre for a in args)))
                     f.write("  ")
                     if rtype:
                         f.write("result_api_ = ")
-                    f.write("gmsh" + module.name+name+"("+", ".join(
-                        list((a.c_cpp_arg for a in args)))+
+                    f.write("gmsh" + module.name+name+"("+",".join(
+                        list((a.c_arg for a in args)))+
                         ");\n")
-                    f.write("".join((a.c_cpp_post for a in args)))
+                    f.write("".join((a.c_post for a in args)))
                     f.write("  } catch(int api_ierr_) {if (ierr) *ierr = api_ierr_;}\n");
                     if rtype :
                         f.write("  return result_api_;\n");
                     f.write("}\n\n")
+
+    def write_python(self) :
+        with open("gmsh.py","w") as f :
+            f.write(python_header)
+            for module in self.modules:
+                f.write("\n## gmsh"+module.name + " ##\n")
+                for (rtype,name,args) in module.fs:
+                    iargs = list(a for a in args if not a.out)
+                    oargs = list(a for a in args if a.out)
+                    f.write("\ndef "+module.name+name+"("
+                            +",".join((a.name for a in iargs))
+                            +"):\n")
+                    for a in args :
+                        if a.python_pre : f.write("    "+a.python_pre+"\n")
+                    f.write("    ierr = c_int()\n")
+                    f.write("    api__result__ = " if rtype is oint else "    ")
+                    f.write("lib.gmshc"+module.name+name+"(\n        "
+                            +",\n        ".join(tuple((a.python_arg for a in args))+("byref(ierr)",))
+                            +")\n")
+                    f.write("    if ierr.value != 0 :\n")
+                    f.write("        raise ValueError(\"gmsh."+module.name+name+" returned non-zero error code : \"+ str(ierr.value))\n")
+                    r = (["api__result__"]) if rtype else []
+                    r += list((o.python_return for o in oargs))
+                    if len(r) != 0 :
+                        if len(r) == 1 :
+                            f.write("    return "+r[0]+"\n")
+                        else :
+                            f.write("    return (\n        "+",\n        ".join(r)+")\n")
diff --git a/api/Makefile b/api/Makefile
index 88b79cb95c..b99dda85db 100644
--- a/api/Makefile
+++ b/api/Makefile
@@ -1,4 +1,4 @@
 all :
 	python gen.py
-	g++ -c gmshc.cc -shared -o libgmshc.so
-	gcc main.c -L. -L../build -Wl,-rpath=../build -lstdc++ -lgmsh  -lgmshc -lgmsh -o main
+	g++  gmshc.cc -shared -fPIC -L. -L../build -Wl,-rpath=../build -lstdc++ -lgmsh -o libgmshc.so
+	gcc main.c -L. -Wl,-rpath=. -L../build -Wl,-rpath=../build  -lgmshc -lgmsh -lstdc++ -o main
diff --git a/api/gen.py b/api/gen.py
index 5374fd53bf..8917e91b72 100644
--- a/api/gen.py
+++ b/api/gen.py
@@ -270,3 +270,4 @@ api.add_module("Graphics")
 
 api.write_cpp("gmsh")
 api.write_c("gmshc")
+api.write_python()
diff --git a/api/test.py b/api/test.py
new file mode 100644
index 0000000000..76e99afec5
--- /dev/null
+++ b/api/test.py
@@ -0,0 +1,48 @@
+import gmsh
+
+gmsh.Initialize()
+gmsh.Open("square.msh")
+
+gmsh.ModelCreate("square")
+gmsh.ModelGeoAddPoint(0,0,0,0.1,1)
+gmsh.ModelGeoAddPoint(1,0,0,0.1,2)
+gmsh.ModelGeoAddPoint(1,1,0,0.1,3)
+gmsh.ModelGeoAddPoint(0,1,0,0.1,4)
+gmsh.ModelGeoAddLine(1,2,1)
+gmsh.ModelGeoAddLine(2,3,2)
+gmsh.ModelGeoAddLine(3,4,3)
+line4 = gmsh.ModelGeoAddLine(4,1,-1)
+print("line4 received tag ", line4)
+gmsh.ModelGeoAddLineLoop([1,2,3,line4],1)
+gmsh.ModelGeoAddPlaneSurface([1],6)
+gmsh.ModelGeoSynchronize()
+
+ptag = gmsh.ModelAddPhysicalGroup(1,[1,2,3,4],-1)
+ent = gmsh.ModelGetEntitiesForPhysicalGroup(1,ptag)
+print("new physical group ",ptag,":",ent, type(ent))
+
+gmsh.ModelAddPhysicalGroup(2,[6],-1)
+
+print(gmsh.OptionGetString("General.BuildOptions"))
+print(gmsh.OptionGetNumber("Mesh.Algorithm"))
+gmsh.OptionSetNumber("Mesh.Algorithm", 3.0)
+print(gmsh.OptionGetNumber("Mesh.Algorithm"))
+gmsh.ModelMesh(2)
+gmsh.Export("square.msh")
+
+print("Entities")
+entities = gmsh.ModelGetEntities(-1)
+for e in entities :
+    print("entity ",e)
+    types,tags,vertices = gmsh.ModelGetMeshElements(e[0],e[1])
+    for i in range(len(types)):
+        print("type ", types[i])
+        print("tags : ", list(tags[i]))
+        print("vertices : ", list(vertices[i]))
+
+
+print("Vertices")
+tags, coord, _ = gmsh.ModelGetMeshVertices(2,6)
+print(tags)
+print(coord)
+gmsh.Finalize()
-- 
GitLab