8606db59abff816db95a79c25a9f51b7c7aab263
[libguestfs.git] / generator / generator_python.ml
1 (* libguestfs
2  * Copyright (C) 2009-2011 Red Hat Inc.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  *)
18
19 (* Please read generator/README first. *)
20
21 open Printf
22
23 open Generator_types
24 open Generator_utils
25 open Generator_pr
26 open Generator_docstrings
27 open Generator_optgroups
28 open Generator_actions
29 open Generator_structs
30 open Generator_c
31
32 (* Generate Python C module. *)
33 let rec generate_python_c () =
34   generate_header CStyle LGPLv2plus;
35
36   pr "\
37 #define PY_SSIZE_T_CLEAN 1
38 #include <Python.h>
39
40 #if PY_VERSION_HEX < 0x02050000
41 typedef int Py_ssize_t;
42 #define PY_SSIZE_T_MAX INT_MAX
43 #define PY_SSIZE_T_MIN INT_MIN
44 #endif
45
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <assert.h>
49
50 #include \"guestfs.h\"
51
52 #ifndef HAVE_PYCAPSULE_NEW
53 typedef struct {
54   PyObject_HEAD
55   guestfs_h *g;
56 } Pyguestfs_Object;
57 #endif
58
59 static guestfs_h *
60 get_handle (PyObject *obj)
61 {
62   assert (obj);
63   assert (obj != Py_None);
64 #ifndef HAVE_PYCAPSULE_NEW
65   return ((Pyguestfs_Object *) obj)->g;
66 #else
67   return (guestfs_h*) PyCapsule_GetPointer(obj, \"guestfs_h\");
68 #endif
69 }
70
71 static PyObject *
72 put_handle (guestfs_h *g)
73 {
74   assert (g);
75 #ifndef HAVE_PYCAPSULE_NEW
76   return
77     PyCObject_FromVoidPtrAndDesc ((void *) g, (char *) \"guestfs_h\", NULL);
78 #else
79   return PyCapsule_New ((void *) g, \"guestfs_h\", NULL);
80 #endif
81 }
82
83 /* This list should be freed (but not the strings) after use. */
84 static char **
85 get_string_list (PyObject *obj)
86 {
87   size_t i, len;
88   char **r;
89
90   assert (obj);
91
92   if (!PyList_Check (obj)) {
93     PyErr_SetString (PyExc_RuntimeError, \"expecting a list parameter\");
94     return NULL;
95   }
96
97   Py_ssize_t slen = PyList_Size (obj);
98   if (slen == -1) {
99     PyErr_SetString (PyExc_RuntimeError, \"get_string_list: PyList_Size failure\");
100     return NULL;
101   }
102   len = (size_t) slen;
103   r = malloc (sizeof (char *) * (len+1));
104   if (r == NULL) {
105     PyErr_SetString (PyExc_RuntimeError, \"get_string_list: out of memory\");
106     return NULL;
107   }
108
109   for (i = 0; i < len; ++i)
110     r[i] = PyString_AsString (PyList_GetItem (obj, i));
111   r[len] = NULL;
112
113   return r;
114 }
115
116 static PyObject *
117 put_string_list (char * const * const argv)
118 {
119   PyObject *list;
120   int argc, i;
121
122   for (argc = 0; argv[argc] != NULL; ++argc)
123     ;
124
125   list = PyList_New (argc);
126   for (i = 0; i < argc; ++i)
127     PyList_SetItem (list, i, PyString_FromString (argv[i]));
128
129   return list;
130 }
131
132 static PyObject *
133 put_table (char * const * const argv)
134 {
135   PyObject *list, *item;
136   int argc, i;
137
138   for (argc = 0; argv[argc] != NULL; ++argc)
139     ;
140
141   list = PyList_New (argc >> 1);
142   for (i = 0; i < argc; i += 2) {
143     item = PyTuple_New (2);
144     PyTuple_SetItem (item, 0, PyString_FromString (argv[i]));
145     PyTuple_SetItem (item, 1, PyString_FromString (argv[i+1]));
146     PyList_SetItem (list, i >> 1, item);
147   }
148
149   return list;
150 }
151
152 static void
153 free_strings (char **argv)
154 {
155   int argc;
156
157   for (argc = 0; argv[argc] != NULL; ++argc)
158     free (argv[argc]);
159   free (argv);
160 }
161
162 static PyObject *
163 py_guestfs_create (PyObject *self, PyObject *args)
164 {
165   guestfs_h *g;
166
167   g = guestfs_create ();
168   if (g == NULL) {
169     PyErr_SetString (PyExc_RuntimeError,
170                      \"guestfs.create: failed to allocate handle\");
171     return NULL;
172   }
173   guestfs_set_error_handler (g, NULL, NULL);
174   /* This can return NULL, but in that case put_handle will have
175    * set the Python error string.
176    */
177   return put_handle (g);
178 }
179
180 static PyObject *
181 py_guestfs_close (PyObject *self, PyObject *args)
182 {
183   PyThreadState *py_save = NULL;
184   PyObject *py_g;
185   guestfs_h *g;
186
187   if (!PyArg_ParseTuple (args, (char *) \"O:guestfs_close\", &py_g))
188     return NULL;
189   g = get_handle (py_g);
190
191   if (PyEval_ThreadsInitialized ())
192     py_save = PyEval_SaveThread ();
193   guestfs_close (g);
194   if (PyEval_ThreadsInitialized ())
195     PyEval_RestoreThread (py_save);
196
197   Py_INCREF (Py_None);
198   return Py_None;
199 }
200
201 ";
202
203   let emit_put_list_function typ =
204     pr "static PyObject *\n";
205     pr "put_%s_list (struct guestfs_%s_list *%ss)\n" typ typ typ;
206     pr "{\n";
207     pr "  PyObject *list;\n";
208     pr "  size_t i;\n";
209     pr "\n";
210     pr "  list = PyList_New (%ss->len);\n" typ;
211     pr "  for (i = 0; i < %ss->len; ++i)\n" typ;
212     pr "    PyList_SetItem (list, i, put_%s (&%ss->val[i]));\n" typ typ;
213     pr "  return list;\n";
214     pr "};\n";
215     pr "\n"
216   in
217
218   (* Structures, turned into Python dictionaries. *)
219   List.iter (
220     fun (typ, cols) ->
221       pr "static PyObject *\n";
222       pr "put_%s (struct guestfs_%s *%s)\n" typ typ typ;
223       pr "{\n";
224       pr "  PyObject *dict;\n";
225       pr "\n";
226       pr "  dict = PyDict_New ();\n";
227       List.iter (
228         function
229         | name, FString ->
230             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
231             pr "                        PyString_FromString (%s->%s));\n"
232               typ name
233         | name, FBuffer ->
234             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
235             pr "                        PyString_FromStringAndSize (%s->%s, %s->%s_len));\n"
236               typ name typ name
237         | name, FUUID ->
238             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
239             pr "                        PyString_FromStringAndSize (%s->%s, 32));\n"
240               typ name
241         | name, (FBytes|FUInt64) ->
242             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
243             pr "                        PyLong_FromUnsignedLongLong (%s->%s));\n"
244               typ name
245         | name, FInt64 ->
246             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
247             pr "                        PyLong_FromLongLong (%s->%s));\n"
248               typ name
249         | name, FUInt32 ->
250             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
251             pr "                        PyLong_FromUnsignedLong (%s->%s));\n"
252               typ name
253         | name, FInt32 ->
254             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
255             pr "                        PyLong_FromLong (%s->%s));\n"
256               typ name
257         | name, FOptPercent ->
258             pr "  if (%s->%s >= 0)\n" typ name;
259             pr "    PyDict_SetItemString (dict, \"%s\",\n" name;
260             pr "                          PyFloat_FromDouble ((double) %s->%s));\n"
261               typ name;
262             pr "  else {\n";
263             pr "    Py_INCREF (Py_None);\n";
264             pr "    PyDict_SetItemString (dict, \"%s\", Py_None);\n" name;
265             pr "  }\n"
266         | name, FChar ->
267             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
268             pr "                        PyString_FromStringAndSize (&dirent->%s, 1));\n" name
269       ) cols;
270       pr "  return dict;\n";
271       pr "};\n";
272       pr "\n";
273
274   ) structs;
275
276   (* Emit a put_TYPE_list function definition only if that function is used. *)
277   List.iter (
278     function
279     | typ, (RStructListOnly | RStructAndList) ->
280         (* generate the function for typ *)
281         emit_put_list_function typ
282     | typ, _ -> () (* empty *)
283   ) (rstructs_used_by all_functions);
284
285   (* Python wrapper functions. *)
286   List.iter (
287     fun (name, (ret, args, optargs as style), _, _, _, _, _) ->
288       pr "static PyObject *\n";
289       pr "py_guestfs_%s (PyObject *self, PyObject *args)\n" name;
290       pr "{\n";
291
292       pr "  PyThreadState *py_save = NULL;\n";
293       pr "  PyObject *py_g;\n";
294       pr "  guestfs_h *g;\n";
295       pr "  PyObject *py_r;\n";
296
297       if optargs <> [] then (
298         pr "  struct guestfs_%s_argv optargs_s;\n" name;
299         pr "  struct guestfs_%s_argv *optargs = &optargs_s;\n" name;
300       );
301
302       (match ret with
303        | RErr | RInt _ | RBool _ -> pr "  int r;\n"
304        | RInt64 _ -> pr "  int64_t r;\n"
305        | RConstString _ | RConstOptString _ ->
306            pr "  const char *r;\n"
307        | RString _ -> pr "  char *r;\n"
308        | RStringList _ | RHashtable _ -> pr "  char **r;\n"
309        | RStruct (_, typ) -> pr "  struct guestfs_%s *r;\n" typ
310        | RStructList (_, typ) ->
311            pr "  struct guestfs_%s_list *r;\n" typ
312        | RBufferOut _ ->
313            pr "  char *r;\n";
314            pr "  size_t size;\n"
315       );
316
317       List.iter (
318         function
319         | Pathname n | Device n | Dev_or_Path n | String n | Key n
320         | FileIn n | FileOut n ->
321             pr "  const char *%s;\n" n
322         | OptString n -> pr "  const char *%s;\n" n
323         | BufferIn n ->
324             pr "  const char *%s;\n" n;
325             pr "  Py_ssize_t %s_size;\n" n
326         | StringList n | DeviceList n ->
327             pr "  PyObject *py_%s;\n" n;
328             pr "  char **%s;\n" n
329         | Bool n -> pr "  int %s;\n" n
330         | Int n -> pr "  int %s;\n" n
331         | Int64 n -> pr "  long long %s;\n" n
332         | Pointer (t, n) ->
333             pr "  long long %s_int64;\n" n;
334             pr "  %s %s;\n" t n
335       ) args;
336
337       if optargs <> [] then (
338         (* XXX This is horrible.  We have to use sentinel values on the
339          * Python side to denote values not set.
340          *)
341         (* Since we don't know if Python types will exactly match
342          * structure types, declare some local variables here.
343          *)
344         List.iter (
345           function
346           | Bool n
347           | Int n -> pr "  int optargs_t_%s = -1;\n" n
348           | Int64 n -> pr "  long long optargs_t_%s = -1;\n" n
349           | String n -> pr "  const char *optargs_t_%s = NULL;\n" n
350           | _ -> assert false
351         ) optargs
352       );
353
354       pr "\n";
355
356       if optargs <> [] then (
357         pr "  optargs_s.bitmask = 0;\n";
358         pr "\n"
359       );
360
361       (* Convert the required parameters. *)
362       pr "  if (!PyArg_ParseTuple (args, (char *) \"O";
363       List.iter (
364         function
365         | Pathname _ | Device _ | Dev_or_Path _ | String _ | Key _
366         | FileIn _ | FileOut _ -> pr "s"
367         | OptString _ -> pr "z"
368         | StringList _ | DeviceList _ -> pr "O"
369         | Bool _ -> pr "i" (* XXX Python has booleans? *)
370         | Int _ -> pr "i"
371         | Int64 _ | Pointer _ ->
372             (* XXX Whoever thought it was a good idea to
373              * emulate C's int/long/long long in Python?
374              *)
375             pr "L"
376         | BufferIn _ -> pr "s#"
377       ) args;
378
379       (* Optional parameters. *)
380       if optargs <> [] then (
381         List.iter (
382           function
383           | Bool _ | Int _ -> pr "i"
384           | Int64 _ -> pr "L"
385           | String _ -> pr "z" (* because we use None to mean not set *)
386           | _ -> assert false
387         ) optargs;
388       );
389
390       pr ":guestfs_%s\",\n" name;
391       pr "                         &py_g";
392       List.iter (
393         function
394         | Pathname n | Device n | Dev_or_Path n | String n | Key n
395         | FileIn n | FileOut n -> pr ", &%s" n
396         | OptString n -> pr ", &%s" n
397         | StringList n | DeviceList n -> pr ", &py_%s" n
398         | Bool n -> pr ", &%s" n
399         | Int n -> pr ", &%s" n
400         | Int64 n -> pr ", &%s" n
401         | Pointer (_, n) -> pr ", &%s_int64" n
402         | BufferIn n -> pr ", &%s, &%s_size" n n
403       ) args;
404
405       List.iter (
406         function
407         | Bool n | Int n | Int64 n | String n -> pr ", &optargs_t_%s" n
408         | _ -> assert false
409       ) optargs;
410
411       pr "))\n";
412       pr "    return NULL;\n";
413
414       pr "  g = get_handle (py_g);\n";
415       List.iter (
416         function
417         | Pathname _ | Device _ | Dev_or_Path _ | String _ | Key _
418         | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ | Int64 _
419         | BufferIn _ -> ()
420         | StringList n | DeviceList n ->
421             pr "  %s = get_string_list (py_%s);\n" n n;
422             pr "  if (!%s) return NULL;\n" n
423         | Pointer (t, n) ->
424             pr "  %s = (%s) (intptr_t) %s_int64;\n" n t n
425       ) args;
426
427       pr "\n";
428
429       if optargs <> [] then (
430         let uc_name = String.uppercase name in
431         List.iter (
432           fun argt ->
433             let n = name_of_argt argt in
434             let uc_n = String.uppercase n in
435             pr "  if (optargs_t_%s != " n;
436             (match argt with
437              | Bool _ | Int _ | Int64 _ -> pr "-1"
438              | String _ -> pr "NULL"
439              | _ -> assert false
440             );
441             pr ") {\n";
442             pr "    optargs_s.%s = optargs_t_%s;\n" n n;
443             pr "    optargs_s.bitmask |= GUESTFS_%s_%s_BITMASK;\n" uc_name uc_n;
444             pr "  }\n"
445         ) optargs;
446         pr "\n"
447       );
448
449       (* Release Python GIL while running.  This code is from
450        * libvirt/python/typewrappers.h.  Thanks to Dan Berrange for
451        * showing us how to do this properly.
452        *)
453       pr "  if (PyEval_ThreadsInitialized ())\n";
454       pr "    py_save = PyEval_SaveThread ();\n";
455       pr "\n";
456
457       if optargs = [] then
458         pr "  r = guestfs_%s " name
459       else
460         pr "  r = guestfs_%s_argv " name;
461       generate_c_call_args ~handle:"g" style;
462       pr ";\n";
463
464       pr "\n";
465       pr "  if (PyEval_ThreadsInitialized ())\n";
466       pr "    PyEval_RestoreThread (py_save);\n";
467       pr "\n";
468
469       List.iter (
470         function
471         | Pathname _ | Device _ | Dev_or_Path _ | String _ | Key _
472         | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ | Int64 _
473         | BufferIn _ | Pointer _ -> ()
474         | StringList n | DeviceList n ->
475             pr "  free (%s);\n" n
476       ) args;
477
478       (match errcode_of_ret ret with
479        | `CannotReturnError -> ()
480        | `ErrorIsMinusOne ->
481            pr "  if (r == -1) {\n";
482            pr "    PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));\n";
483            pr "    return NULL;\n";
484            pr "  }\n"
485        | `ErrorIsNULL ->
486            pr "  if (r == NULL) {\n";
487            pr "    PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));\n";
488            pr "    return NULL;\n";
489            pr "  }\n"
490       );
491       pr "\n";
492
493       (match ret with
494        | RErr ->
495            pr "  Py_INCREF (Py_None);\n";
496            pr "  py_r = Py_None;\n"
497        | RInt _
498        | RBool _ -> pr "  py_r = PyInt_FromLong ((long) r);\n"
499        | RInt64 _ -> pr "  py_r = PyLong_FromLongLong (r);\n"
500        | RConstString _ -> pr "  py_r = PyString_FromString (r);\n"
501        | RConstOptString _ ->
502            pr "  if (r)\n";
503            pr "    py_r = PyString_FromString (r);\n";
504            pr "  else {\n";
505            pr "    Py_INCREF (Py_None);\n";
506            pr "    py_r = Py_None;\n";
507            pr "  }\n"
508        | RString _ ->
509            pr "  py_r = PyString_FromString (r);\n";
510            pr "  free (r);\n"
511        | RStringList _ ->
512            pr "  py_r = put_string_list (r);\n";
513            pr "  free_strings (r);\n"
514        | RStruct (_, typ) ->
515            pr "  py_r = put_%s (r);\n" typ;
516            pr "  guestfs_free_%s (r);\n" typ
517        | RStructList (_, typ) ->
518            pr "  py_r = put_%s_list (r);\n" typ;
519            pr "  guestfs_free_%s_list (r);\n" typ
520        | RHashtable n ->
521            pr "  py_r = put_table (r);\n";
522            pr "  free_strings (r);\n"
523        | RBufferOut _ ->
524            pr "  py_r = PyString_FromStringAndSize (r, size);\n";
525            pr "  free (r);\n"
526       );
527
528       pr "  return py_r;\n";
529       pr "}\n";
530       pr "\n"
531   ) all_functions;
532
533   (* Table of functions. *)
534   pr "static PyMethodDef methods[] = {\n";
535   pr "  { (char *) \"create\", py_guestfs_create, METH_VARARGS, NULL },\n";
536   pr "  { (char *) \"close\", py_guestfs_close, METH_VARARGS, NULL },\n";
537   List.iter (
538     fun (name, _, _, _, _, _, _) ->
539       pr "  { (char *) \"%s\", py_guestfs_%s, METH_VARARGS, NULL },\n"
540         name name
541   ) all_functions;
542   pr "  { NULL, NULL, 0, NULL }\n";
543   pr "};\n";
544   pr "\n";
545
546   (* Init function. *)
547   pr "\
548 void
549 initlibguestfsmod (void)
550 {
551   static int initialized = 0;
552
553   if (initialized) return;
554   Py_InitModule ((char *) \"libguestfsmod\", methods);
555   initialized = 1;
556 }
557 "
558
559 (* Generate Python module. *)
560 and generate_python_py () =
561   generate_header HashStyle LGPLv2plus;
562
563   pr "\
564 u\"\"\"Python bindings for libguestfs
565
566 import guestfs
567 g = guestfs.GuestFS ()
568 g.add_drive_opts (\"guest.img\", format=\"raw\")
569 g.launch ()
570 parts = g.list_partitions ()
571
572 The guestfs module provides a Python binding to the libguestfs API
573 for examining and modifying virtual machine disk images.
574
575 Amongst the things this is good for: making batch configuration
576 changes to guests, getting disk used/free statistics (see also:
577 virt-df), migrating between virtualization systems (see also:
578 virt-p2v), performing partial backups, performing partial guest
579 clones, cloning guests and changing registry/UUID/hostname info, and
580 much else besides.
581
582 Libguestfs uses Linux kernel and qemu code, and can access any type of
583 guest filesystem that Linux and qemu can, including but not limited
584 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
585 schemes, qcow, qcow2, vmdk.
586
587 Libguestfs provides ways to enumerate guest storage (eg. partitions,
588 LVs, what filesystem is in each LV, etc.).  It can also run commands
589 in the context of the guest.  Also you can access filesystems over
590 FUSE.
591
592 Errors which happen while using the API are turned into Python
593 RuntimeError exceptions.
594
595 To create a guestfs handle you usually have to perform the following
596 sequence of calls:
597
598 # Create the handle, call add_drive* at least once, and possibly
599 # several times if the guest has multiple block devices:
600 g = guestfs.GuestFS ()
601 g.add_drive_opts (\"guest.img\", format=\"raw\")
602
603 # Launch the qemu subprocess and wait for it to become ready:
604 g.launch ()
605
606 # Now you can issue commands, for example:
607 logvols = g.lvs ()
608
609 \"\"\"
610
611 import libguestfsmod
612
613 class GuestFS:
614     \"\"\"Instances of this class are libguestfs API handles.\"\"\"
615
616     def __init__ (self):
617         \"\"\"Create a new libguestfs handle.\"\"\"
618         self._o = libguestfsmod.create ()
619
620     def __del__ (self):
621         libguestfsmod.close (self._o)
622
623 ";
624
625   List.iter (
626     fun (name, (ret, args, optargs), _, flags, _, _, longdesc) ->
627       pr "    def %s (self" name;
628       List.iter (fun arg -> pr ", %s" (name_of_argt arg)) args;
629       List.iter (
630         function
631         | Bool n | Int n | Int64 n -> pr ", %s=-1" n
632         | String n -> pr ", %s=None" n
633         | _ -> assert false
634       ) optargs;
635       pr "):\n";
636
637       if not (List.mem NotInDocs flags) then (
638         let doc = replace_str longdesc "C<guestfs_" "C<g." in
639         let doc =
640           match ret with
641           | RErr | RInt _ | RInt64 _ | RBool _
642           | RConstOptString _ | RConstString _
643           | RString _ | RBufferOut _ -> doc
644           | RStringList _ ->
645               doc ^ "\n\nThis function returns a list of strings."
646           | RStruct (_, typ) ->
647               doc ^ sprintf "\n\nThis function returns a dictionary, with keys matching the various fields in the guestfs_%s structure." typ
648           | RStructList (_, typ) ->
649               doc ^ sprintf "\n\nThis function returns a list of %ss.  Each %s is represented as a dictionary." typ typ
650           | RHashtable _ ->
651               doc ^ "\n\nThis function returns a dictionary." in
652         let doc =
653           if List.mem ProtocolLimitWarning flags then
654             doc ^ "\n\n" ^ protocol_limit_warning
655           else doc in
656         let doc =
657           if List.mem DangerWillRobinson flags then
658             doc ^ "\n\n" ^ danger_will_robinson
659           else doc in
660         let doc =
661           match deprecation_notice flags with
662           | None -> doc
663           | Some txt -> doc ^ "\n\n" ^ txt in
664         let doc = pod2text ~width:60 name doc in
665         let doc = List.map (fun line -> replace_str line "\\" "\\\\") doc in
666         let doc = String.concat "\n        " doc in
667         pr "        u\"\"\"%s\"\"\"\n" doc;
668       );
669       (* Callers might pass in iterables instead of plain lists;
670        * convert those to plain lists because the C side of things
671        * cannot deal with iterables.  (RHBZ#693306).
672        *)
673       List.iter (
674         function
675         | Pathname _ | Device _ | Dev_or_Path _ | String _ | Key _
676         | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ | Int64 _
677         | BufferIn _ | Pointer _ -> ()
678         | StringList n | DeviceList n ->
679             pr "        %s = list (%s)\n" n n
680       ) args;
681       pr "        return libguestfsmod.%s (self._o" name;
682       List.iter (fun arg -> pr ", %s" (name_of_argt arg)) (args@optargs);
683       pr ")\n\n";
684   ) all_functions