python: Make result wrapping backwards compatible.
[gpgme.git] / lang / python / pyme / results.py
1 # Robust result objects
2 #
3 # Copyright (C) 2016 g10 Code GmbH
4 #
5 # This file is part of GPGME.
6 #
7 # GPGME is free software; you can redistribute it and/or modify it
8 # under the terms of the GNU Lesser General Public License as
9 # published by the Free Software Foundation; either version 2.1 of the
10 # License, or (at your option) any later version.
11 #
12 # GPGME is distributed in the hope that it will be useful, but WITHOUT
13 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 # or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General
15 # Public License for more details.
16 #
17 # You should have received a copy of the GNU Lesser General Public
18 # License along with this program; if not, see <http://www.gnu.org/licenses/>.
19
20 """Robust result objects
21
22 Results returned by the underlying library are fragile, i.e. they are
23 only valid until the next operation is performed in the context.
24
25 We cannot arbitrarily constrain the lifetime of Python objects, we
26 therefore create deep copies of the results.
27
28 """
29
30 class Result(object):
31     """Result object
32
33     Describes the result of an operation.
34
35     """
36
37     """Convert to types"""
38     _type = {}
39
40     """Map functions over list attributes"""
41     _map = {}
42
43     """Automatically copy unless blacklisted"""
44     _blacklist = {
45         'acquire', 'append', 'disown', 'next', 'own', 'this', 'thisown',
46     }
47     def __init__(self, fragile):
48         for key, func in self._type.items():
49             if hasattr(fragile, key):
50                 setattr(self, key, func(getattr(fragile, key)))
51
52         for key, func in self._map.items():
53             if hasattr(fragile, key):
54                 setattr(self, key, list(map(func, getattr(fragile, key))))
55
56         for key in dir(fragile):
57             if key.startswith('_') or key in self._blacklist:
58                 continue
59             if hasattr(self, key):
60                 continue
61
62             setattr(self, key, getattr(fragile, key))
63
64     def __str__(self):
65         return '<{} {}>'.format(
66             self.__class__.__name__,
67             ', '.join('{}: {}'.format(k, getattr(self, k))
68                       for k in dir(self) if not k.startswith('_')))
69
70 class InvalidKey(Result):
71     pass
72
73 class EncryptResult(Result):
74     _map = dict(invalid_recipients=InvalidKey)
75
76 class Recipient(Result):
77     pass
78
79 class DecryptResult(Result):
80     _type = dict(wrong_key_usage=bool)
81     _map = dict(recipients=Recipient)
82
83 class NewSignature(Result):
84     pass
85
86 class SignResult(Result):
87     _map = dict(invalid_signers=InvalidKey, signatures=NewSignature)
88
89 class Notation(Result):
90     pass
91
92 class TofuInfo(Result):
93     pass
94
95 class Signature(Result):
96     _type = dict(wrong_key_usage=bool, chain_model=bool)
97     _map = dict(notations=Notation, tofu=TofuInfo)
98
99 class VerifyResult(Result):
100     _map = dict(signatures=Signature)
101
102 class ImportStatus(Result):
103     pass
104
105 class ImportResult(Result):
106     _map = dict(imports=ImportStatus)
107
108 class GenkeyResult(Result):
109     _type = dict(primary=bool, sub=bool)
110
111 class KeylistResult(Result):
112     _type = dict(truncated=bool)
113
114 class VFSMountResult(Result):
115     pass