Imported Upstream version 1.12.0
[platform/upstream/gpgme.git] / lang / python / gpgme.i
1 /*
2 # Copyright (C) 2016 g10 Code GmbH
3 # Copyright (C) 2004,2008 Igor Belyi <belyi@users.sourceforge.net>
4 # Copyright (C) 2002 John Goerzen <jgoerzen@complete.org>
5 #
6 #    This library is free software; you can redistribute it and/or
7 #    modify it under the terms of the GNU Lesser General Public
8 #    License as published by the Free Software Foundation; either
9 #    version 2.1 of the License, or (at your option) any later version.
10 #
11 #    This library is distributed in the hope that it will be useful,
12 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
13 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 #    Lesser General Public License for more details.
15 #
16 #    You should have received a copy of the GNU Lesser General Public
17 #    License along with this library; if not, write to the Free Software
18 #    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
19 */
20 %module gpgme
21 %include "cpointer.i"
22 %include "cstring.i"
23
24 %{
25 /* We use public symbols (eg. "_obsolete_class") which are marked as
26  * deprecated but we need to keep them.  Silence the warning.  */
27 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
28 %}
29
30 /* Generate doc strings for all methods.
31
32    This will generate docstrings of the form
33
34      gpgme_op_encrypt(ctx, recp, flags, plain, cipher) -> gpgme_error_t
35
36    which we transform into
37
38      ctx.op_encrypt(recp, flags, plain, cipher) -> gpgme_error_t
39
40    for automagically wrapped functions.  */
41 %feature("autodoc", "0");
42
43
44 /* Allow use of Unicode objects, bytes, and None for strings.  */
45 %typemap(in) const char *(PyObject *encodedInput = NULL) {
46   if ($input == Py_None)
47     $1 = NULL;
48   else if (PyUnicode_Check($input))
49     {
50       encodedInput = PyUnicode_AsUTF8String($input);
51       if (encodedInput == NULL)
52         return NULL;
53       $1 = PyBytes_AsString(encodedInput);
54     }
55   else if (PyBytes_Check($input))
56     $1 = PyBytes_AsString($input);
57   else {
58     PyErr_Format(PyExc_TypeError,
59                  "arg %d: expected str, bytes, or None, got %s",
60                  $argnum, $input->ob_type->tp_name);
61     return NULL;
62   }
63 }
64 %typemap(freearg) const char * {
65   Py_XDECREF(encodedInput$argnum);
66 }
67
68 /* Likewise for a list of strings.  */
69 %typemap(in) const char *[] (void *vector = NULL,
70                              size_t size,
71                              PyObject **pyVector = NULL) {
72   /* Check if is a list */
73   if (PyList_Check($input)) {
74     size_t i, j;
75     size = PyList_Size($input);
76     $1 = (char **) (vector = malloc((size+1) * sizeof(char *)));
77     pyVector = calloc(sizeof *pyVector, size);
78
79     for (i = 0; i < size; i++) {
80       PyObject *o = PyList_GetItem($input,i);
81       if (PyUnicode_Check(o))
82         {
83           pyVector[i] = PyUnicode_AsUTF8String(o);
84           if (pyVector[i] == NULL)
85             {
86               free(vector);
87               for (j = 0; j < i; j++)
88                 Py_XDECREF(pyVector[j]);
89               return NULL;
90             }
91           $1[i] = PyBytes_AsString(pyVector[i]);
92         }
93       else if (PyString_Check(o))
94         $1[i] = PyString_AsString(o);
95       else {
96         PyErr_Format(PyExc_TypeError,
97                      "arg %d: list must contain only str or bytes, got %s "
98                      "at position %d",
99                      $argnum, o->ob_type->tp_name, i);
100         free($1);
101         return NULL;
102       }
103     }
104     $1[i] = NULL;
105   } else {
106     PyErr_Format(PyExc_TypeError,
107                  "arg %d: expected a list of str or bytes, got %s",
108                  $argnum, $input->ob_type->tp_name);
109     return NULL;
110   }
111 }
112 %typemap(freearg) const char *[] {
113   size_t i;
114   free(vector$argnum);
115   for (i = 0; i < size$argnum; i++)
116     Py_XDECREF(pyVector$argnum[i]);
117 }
118
119 /* Release returned buffers as necessary.  */
120 %typemap(newfree) char * "gpgme_free($1);";
121 %newobject gpgme_data_release_and_get_mem;
122 %newobject gpgme_pubkey_algo_string;
123 %newobject gpgme_addrspec_from_uid;
124
125 %typemap(arginit) gpgme_key_t [] {
126   $1 = NULL;
127 }
128
129 %typemap(in) gpgme_key_t [] {
130   int i, numb = 0;
131   if (!PySequence_Check($input)) {
132     PyErr_Format(PyExc_ValueError, "arg %d: Expected a list of gpgme_key_t",
133                  $argnum);
134     return NULL;
135   }
136   if((numb = PySequence_Length($input)) != 0) {
137     $1 = (gpgme_key_t*)malloc((numb+1)*sizeof(gpgme_key_t));
138     for(i=0; i<numb; i++) {
139       PyObject *pypointer = PySequence_GetItem($input, i);
140
141       /* input = $input, 1 = $1, 1_descriptor = $1_descriptor */
142       /* &1_descriptor = $&1_descriptor *1_descriptor = $*1_descriptor */
143
144       /* Following code is from swig's python.swg.  */
145       if ((SWIG_ConvertPtr(pypointer,(void **) &$1[i], $*1_descriptor,SWIG_POINTER_EXCEPTION | $disown )) == -1) {
146         Py_DECREF(pypointer);
147         PyErr_Format(PyExc_TypeError,
148                      "arg %d: list must contain only gpgme_key_ts, got %s "
149                      "at position %d",
150                      $argnum, pypointer->ob_type->tp_name, i);
151         free($1);
152         return NULL;
153       }
154       Py_DECREF(pypointer);
155     }
156     $1[numb] = NULL;
157   }
158 }
159 %typemap(freearg) gpgme_key_t [] {
160   if ($1) free($1);
161 }
162
163 /* Special handling for references to our objects.  */
164 %typemap(in) gpgme_data_t DATAIN (gpgme_data_t wrapper = NULL,
165                                   PyObject *bytesio = NULL,
166                                   Py_buffer view, int have_view = 0) {
167   /* If we create a temporary wrapper object, we will store it in
168      wrapperN, where N is $argnum.  Here in this fragment, SWIG will
169      automatically append $argnum.  */
170   memset(&view, 0, sizeof view);
171   if ($input == Py_None)
172     $1 = NULL;
173   else {
174     PyObject *pypointer;
175     pypointer = _gpg_obj2gpgme_data_t($input, $argnum, &wrapper,
176                                        &bytesio, &view);
177     if (pypointer == NULL)
178       return NULL;
179     have_view = !! view.obj;
180
181     /* input = $input, 1 = $1, 1_descriptor = $1_descriptor */
182
183     /* Following code is from swig's python.swg.  */
184
185     if ((SWIG_ConvertPtr(pypointer,(void **) &$1, $1_descriptor,
186          SWIG_POINTER_EXCEPTION | $disown )) == -1) {
187       Py_DECREF(pypointer);
188       return NULL;
189     }
190     Py_DECREF(pypointer);
191   }
192 }
193
194 #if HAVE_DATA_H
195 /* If we are doing an in-tree build, we can use the internal
196    representation of struct gpgme_data for an very efficient check if
197    the buffer has been modified.  */
198 %{
199 #include "data.h"       /* For struct gpgme_data.  */
200 %}
201 #endif
202
203 %typemap(freearg) gpgme_data_t DATAIN {
204   /* See whether we need to update the Python buffer.  */
205   if (resultobj && wrapper$argnum && view$argnum.buf)
206     {
207       int dirty;
208       char *new_data = NULL;
209       size_t new_size;
210
211 #if HAVE_DATA_H
212       new_data = wrapper$argnum->data.mem.buffer;
213       new_size = wrapper$argnum->data.mem.length;
214       dirty = new_data != NULL;
215 #else
216       new_data = gpgme_data_release_and_get_mem (wrapper$argnum, &new_size);
217       wrapper$argnum = NULL;
218       dirty = new_size != view$argnum.len
219         || memcmp (new_data, view$argnum.buf, view$argnum.len);
220 #endif
221
222       if (dirty)
223         {
224           /* The buffer is dirty.  */
225           if (view$argnum.readonly)
226             {
227               Py_XDECREF(resultobj);
228               resultobj = NULL;
229               PyErr_SetString(PyExc_ValueError,
230                               "cannot update read-only buffer");
231             }
232
233           /* See if we need to truncate the buffer.  */
234           if (resultobj && view$argnum.len != new_size)
235             {
236               if (bytesio$argnum == NULL)
237                 {
238                   Py_XDECREF(resultobj);
239                   resultobj = NULL;
240                   PyErr_SetString(PyExc_ValueError, "cannot resize buffer");
241                 }
242               else
243                 {
244                   PyObject *retval;
245                   PyBuffer_Release(&view$argnum);
246                   assert(view$argnum.obj == NULL);
247                   retval = PyObject_CallMethod(bytesio$argnum, "truncate",
248                                                "l", (long) new_size);
249                   if (retval == NULL)
250                     {
251                       Py_XDECREF(resultobj);
252                       resultobj = NULL;
253                     }
254                   else
255                     {
256                       Py_DECREF(retval);
257
258                       retval = PyObject_CallMethod(bytesio$argnum,
259                                                    "getbuffer", NULL);
260                       if (retval == NULL
261                           || PyObject_GetBuffer(retval, &view$argnum,
262                                            PyBUF_SIMPLE|PyBUF_WRITABLE) < 0)
263                         {
264                           Py_XDECREF(resultobj);
265                           resultobj = NULL;
266                         }
267
268                       Py_XDECREF(retval);
269
270                       if (resultobj && view$argnum.len
271                           != new_size)
272                         {
273                           Py_XDECREF(resultobj);
274                           resultobj = NULL;
275                           PyErr_Format(PyExc_ValueError,
276                                        "Expected buffer of length %zu, got %zi",
277                                        new_size,
278                                        view$argnum.len);
279                         }
280                     }
281                 }
282             }
283           if (resultobj)
284             memcpy(view$argnum.buf, new_data, new_size);
285         }
286 #if ! HAVE_DATA_H
287       free (new_data);
288 #endif
289     }
290
291   /* Free the temporary wrapper, if any.  */
292   if (wrapper$argnum)
293     gpgme_data_release(wrapper$argnum);
294   Py_XDECREF (bytesio$argnum);
295   if (have_view$argnum && view$argnum.buf)
296     PyBuffer_Release(&view$argnum);
297 }
298
299 %apply gpgme_data_t DATAIN {gpgme_data_t plain, gpgme_data_t cipher,
300                         gpgme_data_t sig, gpgme_data_t signed_text,
301                         gpgme_data_t plaintext, gpgme_data_t keydata,
302                         gpgme_data_t pubkey, gpgme_data_t seckey,
303                         gpgme_data_t out, gpgme_data_t data};
304
305 /* SWIG has problems interpreting ssize_t, off_t or gpgme_error_t in
306    gpgme.h.  */
307 %typemap(out) ssize_t, gpgme_error_t, gpgme_err_code_t, gpgme_err_source_t, gpg_error_t {
308   $result = PyLong_FromLong($1);
309 }
310
311 %typemap(in) ssize_t, gpgme_error_t, gpgme_err_code_t, gpgme_err_source_t, gpg_error_t {
312   if (PyLong_Check($input))
313     $1 = PyLong_AsLong($input);
314 #if PY_MAJOR_VERSION < 3
315   else if (PyInt_Check($input))
316     $1 = PyInt_AsLong($input);
317 #endif
318   else
319     PyErr_SetString(PyExc_TypeError, "Numeric argument expected");
320 }
321
322 %typemap(out) off_t {
323 #if _FILE_OFFSET_BITS == 64
324   $result = PyLong_FromLongLong($1);
325 #else
326   $result = PyLong_FromLong($1);
327 #endif
328 }
329
330 %typemap(in) off_t {
331   if (PyLong_Check($input))
332 #if _FILE_OFFSET_BITS == 64
333     $1 = PyLong_AsLongLong($input);
334 #else
335     $1 = PyLong_AsLong($input);
336 #endif
337 #if PY_MAJOR_VERSION < 3
338   else if (PyInt_Check($input))
339     $1 = PyInt_AsLong($input);
340 #endif
341   else
342     PyErr_SetString(PyExc_TypeError, "Numeric argument expected");
343 }
344
345 /* Those are for gpgme_data_read() and gpgme_strerror_r().  */
346 %typemap(in) (void *buffer, size_t size), (char *buf, size_t buflen) {
347   {
348     long tmp$argnum;
349     if (PyLong_Check($input))
350       tmp$argnum = PyLong_AsLong($input);
351 #if PY_MAJOR_VERSION < 3
352     else if (PyInt_Check($input))
353       tmp$argnum = PyInt_AsLong($input);
354 #endif
355     else
356       {
357         PyErr_SetString(PyExc_TypeError, "Numeric argument expected");
358         return NULL;
359       }
360
361     if (tmp$argnum < 0) {
362       PyErr_SetString(PyExc_ValueError, "Positive integer expected");
363       return NULL;
364     }
365     $2 = (size_t) tmp$argnum;
366     $1 = ($1_ltype) malloc($2+1);
367   }
368 }
369 %typemap(argout) (void *buffer, size_t size), (char *buf, size_t buflen) {
370   Py_XDECREF($result);   /* Blow away any previous result */
371   if (result < 0) {      /* Check for I/O error */
372     free($1);
373     return PyErr_SetFromErrno(PyExc_RuntimeError);
374   }
375   $result = PyBytes_FromStringAndSize($1,result);
376   free($1);
377 }
378
379 /* For gpgme_data_write, but should be universal.  */
380 %typemap(in) (const void *buffer, size_t size)(PyObject *encodedInput = NULL) {
381   Py_ssize_t ssize;
382
383   if ($input == Py_None)
384     $1 = NULL, $2 = 0;
385   else if (PyUnicode_Check($input))
386     {
387       encodedInput = PyUnicode_AsUTF8String($input);
388       if (encodedInput == NULL)
389         return NULL;
390       if (PyBytes_AsStringAndSize(encodedInput, (char **) &$1, &ssize) == -1)
391         {
392           Py_DECREF(encodedInput);
393           return NULL;
394         }
395     }
396   else if (PyBytes_Check($input))
397     PyBytes_AsStringAndSize($input, (char **) &$1, &ssize);
398   else {
399     PyErr_Format(PyExc_TypeError,
400                  "arg %d: expected str, bytes, or None, got %s",
401                  $argnum, $input->ob_type->tp_name);
402     return NULL;
403   }
404
405   if (! $1)
406     $2 = 0;
407   else
408     {
409       assert (ssize >= 0);
410       $2 = (size_t) ssize;
411     }
412 }
413 %typemap(freearg) (const void *buffer, size_t size) {
414   Py_XDECREF(encodedInput$argnum);
415 }
416
417 /* Make types containing 'next' field to be lists.  */
418 %ignore next;
419 %typemap(out) gpgme_sig_notation_t, gpgme_subkey_t,
420    gpgme_key_sig_t, gpgme_user_id_t, gpgme_invalid_key_t,
421    gpgme_recipient_t, gpgme_new_signature_t, gpgme_signature_t,
422    gpgme_import_status_t, gpgme_conf_arg_t, gpgme_conf_opt_t,
423    gpgme_conf_comp_t, gpgme_tofu_info_t {
424   int i;
425   int size = 0;
426   $1_ltype curr;
427   for (curr = $1; curr != NULL; curr = curr->next) {
428     size++;
429   }
430   $result = PyList_New(size);
431   for (i=0,curr=$1; i<size; i++,curr=curr->next) {
432     PyObject *o = SWIG_NewPointerObj(SWIG_as_voidptr(curr), $1_descriptor, %newpointer_flags);
433     PyList_SetItem($result, i, o);
434   }
435 }
436
437 \f
438
439 /* Wrap the fragile result objects into robust Python ones.  */
440 %define wrapresult(cls, name)
441 %typemap(out) cls {
442   PyObject *fragile;
443   fragile = SWIG_NewPointerObj(SWIG_as_voidptr($1), $1_descriptor,
444                                %newpointer_flags);
445   $result = _gpg_wrap_result(fragile, name);
446   Py_DECREF(fragile);
447 }
448 %enddef
449
450 wrapresult(gpgme_encrypt_result_t, "EncryptResult")
451 wrapresult(gpgme_decrypt_result_t, "DecryptResult")
452 wrapresult(gpgme_sign_result_t, "SignResult")
453 wrapresult(gpgme_verify_result_t, "VerifyResult")
454 wrapresult(gpgme_import_result_t, "ImportResult")
455 wrapresult(gpgme_genkey_result_t, "GenkeyResult")
456 wrapresult(gpgme_keylist_result_t, "KeylistResult")
457 wrapresult(gpgme_vfs_mount_result_t, "VFSMountResult")
458
459 %typemap(out) gpgme_engine_info_t {
460   int i;
461   int size = 0;
462   $1_ltype curr;
463   for (curr = $1; curr != NULL; curr = curr->next) {
464     size++;
465   }
466   $result = PyList_New(size);
467   if ($result == NULL)
468     return NULL;        /* raise */
469   for (i=0,curr=$1; i<size; i++,curr=curr->next) {
470     PyObject *fragile, *o;
471     fragile = SWIG_NewPointerObj(SWIG_as_voidptr(curr), $1_descriptor,
472                                  %newpointer_flags);
473     if (fragile == NULL)
474       {
475         Py_DECREF($result);
476         return NULL;    /* raise */
477       }
478     o = _gpg_wrap_result(fragile, "EngineInfo");
479     Py_DECREF(fragile);
480     if (o == NULL)
481       {
482         Py_DECREF($result);
483         return NULL;    /* raise */
484       }
485     PyList_SetItem($result, i, o);
486   }
487 }
488
489 \f
490
491 /* Include mapper for interact callbacks.  */
492 %typemap(in) (gpgme_interact_cb_t fnc, void *fnc_value) {
493   if (! PyTuple_Check($input))
494     return PyErr_Format(PyExc_TypeError, "interact callback must be a tuple");
495   if (PyTuple_Size($input) != 2 && PyTuple_Size($input) != 3)
496     return PyErr_Format(PyExc_TypeError,
497                         "interact callback must be a tuple of size 2 or 3");
498
499   $1 = (gpgme_interact_cb_t) _gpg_interact_cb;
500   $2 = $input;
501 }
502
503 \f
504
505 /* The assuan protocol callbacks.  */
506 %typemap(in) (gpgme_assuan_data_cb_t data_cb, void *data_cb_value) {
507   if ($input == Py_None)
508     $1 = $2 = NULL;
509   else
510     {
511       if (! PyTuple_Check($input))
512         return PyErr_Format(PyExc_TypeError, "callback must be a tuple");
513       if (PyTuple_Size($input) != 2)
514         return PyErr_Format(PyExc_TypeError,
515                             "callback must be a tuple of size 2");
516       if (! PyCallable_Check(PyTuple_GetItem($input, 1)))
517         return PyErr_Format(PyExc_TypeError, "second item must be callable");
518       $1 = _gpg_assuan_data_cb;
519       $2 = $input;
520     }
521 }
522
523 %typemap(in) (gpgme_assuan_inquire_cb_t inq_cb, void *inq_cb_value) {
524   if ($input == Py_None)
525     $1 = $2 = NULL;
526   else
527     {
528       if (! PyTuple_Check($input))
529         return PyErr_Format(PyExc_TypeError, "callback must be a tuple");
530       if (PyTuple_Size($input) != 2)
531         return PyErr_Format(PyExc_TypeError,
532                             "callback must be a tuple of size 2");
533       if (! PyCallable_Check(PyTuple_GetItem($input, 1)))
534         return PyErr_Format(PyExc_TypeError, "second item must be callable");
535       $1 = _gpg_assuan_inquire_cb;
536       $2 = $input;
537     }
538 }
539
540 %typemap(in) (gpgme_assuan_status_cb_t stat_cb, void *stat_cb_value) {
541   if ($input == Py_None)
542     $1 = $2 = NULL;
543   else
544     {
545       if (! PyTuple_Check($input))
546         return PyErr_Format(PyExc_TypeError, "callback must be a tuple");
547       if (PyTuple_Size($input) != 2)
548         return PyErr_Format(PyExc_TypeError,
549                             "callback must be a tuple of size 2");
550       if (! PyCallable_Check(PyTuple_GetItem($input, 1)))
551         return PyErr_Format(PyExc_TypeError, "second item must be callable");
552       $1 = _gpg_assuan_status_cb;
553       $2 = $input;
554     }
555 }
556
557
558 /* With SWIG, you can define default arguments for parameters.
559  * While it's legal in C++ it is not in C, so we cannot change the
560  * already existing gpgme.h. We need, however, to declare the function
561  * *before* SWIG loads it from gpgme.h. Hence, we define it here.     */
562 gpgme_error_t gpgme_op_keylist_start (gpgme_ctx_t ctx,
563                       const char *pattern="",
564                       int secret_only=0);
565
566 /* The whence argument is surprising in Python-land,
567    because BytesIO or StringIO objects do not require it.
568    It defaults to SEEK_SET. Let's do that for Data objects, too */
569 off_t gpgme_data_seek (gpgme_data_t dh, off_t offset, int whence=SEEK_SET);
570
571 /* Include the unmodified <gpgme.h> for cc, and the cleaned-up local
572    version for SWIG.  We do, however, want to hide certain fields on
573    some structs, which we provide prior to including the version for
574    SWIG.  */
575 %{
576 #ifdef HAVE_CONFIG_H
577 #include "config.h"
578 #endif
579
580 #include <gpgme.h>
581 %}
582
583 /* This is for notations, where we want to hide the length fields, and
584  * the unused bit field block.  We silence the warning.  */
585 %warnfilter(302) _gpgme_sig_notation;
586 struct _gpgme_sig_notation
587 {
588   struct _gpgme_sig_notation *next;
589
590   /* If NAME is a null pointer, then VALUE contains a policy URL
591      rather than a notation.  */
592   char *name;
593
594   /* The value of the notation data.  */
595   char *value;
596
597   /* The accumulated flags.  */
598   gpgme_sig_notation_flags_t flags;
599
600   /* Notation data is human-readable.  */
601   unsigned int human_readable : 1;
602
603   /* Notation data is critical.  */
604   unsigned int critical : 1;
605 };
606
607 /* Now include our local modified version.  Any structs defined above
608    are ignored.  */
609 #ifdef HAVE_CONFIG_H
610 %include "config.h"
611 #endif
612
613 %include "gpgme.h"
614
615 %include "errors.i"
616
617 /* Generating and handling pointers-to-pointers.  */
618
619 %pointer_functions(gpgme_ctx_t, gpgme_ctx_t_p);
620 %pointer_functions(gpgme_data_t, gpgme_data_t_p);
621 %pointer_functions(gpgme_key_t, gpgme_key_t_p);
622 %pointer_functions(gpgme_error_t, gpgme_error_t_p);
623 %pointer_functions(gpgme_trust_item_t, gpgme_trust_item_t_p);
624 %pointer_functions(gpgme_engine_info_t, gpgme_engine_info_t_p);
625
626 /* Helper functions.  */
627
628 %{
629 #include <stdio.h>
630 %}
631 FILE *fdopen(int fildes, const char *mode);
632
633 /* We include both headers in the generated c code...  */
634 %{
635 #include "helpers.h"
636 #include "private.h"
637
638 /* SWIG runtime support for helpers.c  */
639 PyObject *
640 _gpg_wrap_gpgme_data_t(gpgme_data_t data)
641 {
642   /*
643    * If SWIG is invoked without -builtin, the macro SWIG_NewPointerObj
644    * expects a variable named "self".
645    *
646    * XXX: It is not quite clear why passing NULL as self is okay, but
647    * it works with -builtin, and it seems to work just fine without
648    * it too.
649    */
650   PyObject* self = NULL;
651   (void) self;
652   return SWIG_NewPointerObj(data, SWIGTYPE_p_gpgme_data, 0);
653 }
654
655 gpgme_ctx_t
656 _gpg_unwrap_gpgme_ctx_t(PyObject *wrapped)
657 {
658   gpgme_ctx_t result;
659   if (SWIG_ConvertPtr(wrapped,
660                       (void **) &result,
661                       SWIGTYPE_p_gpgme_context,
662                       SWIG_POINTER_EXCEPTION) == -1)
663     return NULL;
664   return result;
665 }
666 %}
667
668 /* ... but only the public definitions here.  They will be exposed to
669    the Python world, so let's be careful.  */
670 %include "helpers.h"
671
672
673 %define genericrepr(cls)
674 %pythoncode %{
675     def __repr__(self):
676         names = [name for name in dir(self)
677             if not name.startswith("_") and name != "this"]
678         props = ", ".join(("{}={!r}".format(name, getattr(self, name))
679             for name in names)
680         )
681         return "cls({})".format(props)
682 %}
683
684 %enddef
685
686 %extend _gpgme_key {
687   genericrepr(Key)
688 };
689
690
691 %extend _gpgme_subkey {
692   genericrepr(SubKey)
693 };
694
695 %extend _gpgme_key_sig {
696   genericrepr(KeySig)
697 };
698
699 %extend _gpgme_user_id {
700   genericrepr(UID)
701 };
702
703 %extend _gpgme_tofu_info {
704   genericrepr(TofuInfo)
705 };