Statistics
| Branch: | Tag: | Revision:

root / kamaki / clients / commissioning / utils / argmap.py @ 24ff0a35

History | View | Annotate | Download (8.5 kB)

1
# Copyright 2012 GRNET S.A. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or
4
# without modification, are permitted provided that the following
5
# conditions are met:
6
#
7
#   1. Redistributions of source code must retain the above
8
#      copyright notice, this list of conditions and the following
9
#      disclaimer.
10
#
11
#   2. Redistributions in binary form must reproduce the above
12
#      copyright notice, this list of conditions and the following
13
#      disclaimer in the documentation and/or other materials
14
#      provided with the distribution.
15
#
16
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
# POSSIBILITY OF SUCH DAMAGE.
28
#
29
# The views and conclusions contained in the software and
30
# documentation are those of the authors and should not be
31
# interpreted as representing official policies, either expressed
32
# or implied, of GRNET S.A.
33

    
34
try:
35
    from collections import OrderedDict
36
except ImportError:
37
    from kamaki.clients.commissioning.utils.ordereddict import OrderedDict
38
from itertools import chain
39
from cStringIO import StringIO
40

    
41
ARGMAP_MAGIC = '[=ARGMAP=]'
42

    
43

    
44
class arguments(object):
45
    __slots__ = ('args', 'kw')
46

    
47
    def __init__(self, *args, **kwargs):
48
        self.args = list(args)
49
        kw = OrderedDict()
50
        kwitems = kw.pop('kwitems', None)
51
        if kwitems is not None:
52
            kw.update(kwitems)
53
        kw.update(kwargs)
54
        self.kw = kw
55

    
56
    def __str__(self):
57
        return str(self.args) + '+' + str(self.kw)
58

    
59
    def __repr__(self):
60
        return repr(self.args) + '+' + repr(self.kw)
61

    
62
    def __getitem__(self, key):
63
        if (isinstance(key, int)) or (
64
            isinstance(key, long)) or (
65
            isinstance(key, slice)):
66
                return self.args[key]
67
        else:
68
            return self.kw[key]
69

    
70
    def __setitem__(self, key, value):
71
        if (isinstance(key, int)) or (
72
            isinstance(key, long)) or (
73
            isinstance(key, slice)):
74
                self.args[key] = value
75
        else:
76
            self.kw[key] = value
77

    
78
    def __delitem__(self, key):
79
        if (isinstance(key, int)) or (
80
            isinstance(key, long)) or (
81
            isinstance(key, slice)):
82
                del self.args[key]
83
        else:
84
                del self.kw[key]
85

    
86
    def iteritems(self):
87
        for item in self.args:
88
            yield None, item
89
        for k, v in self.kw:
90
            yield k, v
91

    
92
    def items(self):
93
        return list(self.iteritems())
94

    
95
    def iterkeys(self):
96
        return self.kw.iterkeys()
97

    
98
    def keys(self):
99
        return self.kw.keys()
100

    
101
    def itervalues(self):
102
        return chain(self.args, self.kw.itervalues())
103

    
104
    def values(self):
105
        return list(self.itervalues)
106

    
107
    def append(self, value):
108
        self.args.append(value)
109

    
110

    
111
def argmap_encode(obj, output):
112
    if obj is None:
113
        output('[=null]')
114
        return
115

    
116
    if isinstance(obj, basestring):
117
        if not obj:
118
            output('""')
119
        if isinstance(obj, unicode):
120
            obj = obj.encode('utf-8')
121
        output('"')
122
        start = 0
123
        while 1:
124
            end = obj.find(start) + 1
125
            if end < 0:
126
                break
127
            output(obj[start:end] + '"')
128
            start = end
129
        output(obj[start:])
130
        output('"')
131
        return
132

    
133
    if isinstance(obj, int) or isinstance(obj, long):
134
        output(str(obj))
135
        return
136

    
137
    if hasattr(obj, 'iteritems'):
138
        output('[')
139
        once = 1
140
        for k, v in obj.iteritems():
141
            if once:
142
                once = 0
143
            else:
144
                output(' ')
145
            if k is not None:
146
                argmap_encode(k)
147
                output('=')
148
            argmap_encode(v)
149
        output(']')
150

    
151
    if hasattr(obj, '__iter__'):
152
        output('[')
153
        once = 1
154
        for item in obj:
155
            if once:
156
                once = 0
157
            else:
158
                output(' ')
159
            argmap_encode(item)
160
        output(']')
161

    
162
    m = "Unsupported type '%s'" % (type(obj))
163
    m += ''
164

    
165

    
166
def argmap_decode(inputf, s=None):
167
    if isinstance(inputf, str):
168
        inputf = StringIO(inputf).read
169

    
170
    if s is None:
171
        s = inputf(1)
172

    
173
    while 1:
174
        if not s.isspace():
175
            break
176
        s = inputf(1)
177

    
178
    item = ''
179
    if s == '"':
180
        s = inputf(1)
181
        while 1:
182
            if s == '"':
183
                s = inputf(1)
184
                if s != '"':
185
                    return item, s
186
            item += s
187
            s = inputf(1)
188
    elif s == '[':
189
        item, s = argmap_decode_args(inputf)
190
        return item, s
191
    else:
192
        while 1:
193
            item += s
194
            s = inputf(1)
195
            if s in ' =]':
196
                return item, s
197

    
198

    
199
def argmap_decode_atom(inputf):
200
    s = inputf(4)
201
    if s != 'null':
202
        m = "Invalid atom '%s'" % (s,)
203
        raise ValueError(m)
204
    return None, None
205

    
206

    
207
def argmap_decode_args(inputf):
208
    args = []
209
    append = args.append
210
    s = inputf(1)
211
    key = None
212

    
213
    while 1:
214
        if s is None:
215
            s = inputf(1)
216

    
217
        if s == ']':
218
            if key is not None:
219
                append((None, key))
220
            args.append(ARGMAP_MAGIC)
221
            return args, None
222

    
223
        if s == '=':
224
            if key is None:
225
                atom, s = argmap_decode_atom(inputf)
226
                append((None, atom))
227
            else:
228
                value, s = argmap_decode(inputf)
229
                append((key, value))
230
                key = None
231
        elif s == ' ':
232
            if key is not None:
233
                append((None, key))
234
                key = None
235
            s = inputf(1)
236
        elif s == '':
237
            m = "EOF while scanning for ']'"
238
            raise ValueError(m)
239
        else:
240
            if key is not None:
241
                append((None, key))
242
            key, s = argmap_decode(inputf, s=s)
243

    
244

    
245
def argmap_check(obj):
246
    if hasattr(obj, 'keys') and callable(obj.keys):
247
        # this could cover both cases
248
        return ARGMAP_MAGIC in obj
249
    if hasattr(obj, '__len__'):
250
        length = len(obj)
251
        return length and obj[length - 1] == ARGMAP_MAGIC
252
    return False
253

    
254

    
255
def argmap_unzip_dict(argmap):
256
    if not hasattr(argmap, 'keys'):
257
        m = "argmap unzip dict: not a dict"
258
        raise TypeError(m)
259
    if ARGMAP_MAGIC not in argmap:
260
        m = "argmap unzip dict: magic not found"
261
        raise ValueError(m)
262
    args = argmap.pop(None, [])
263
    kw = OrderedDict(argmap)
264
    del kw[ARGMAP_MAGIC]
265
    return args, kw
266

    
267

    
268
def argmap_unzip_list(argmap):
269
    if not argmap or argmap.pop() != ARGMAP_MAGIC:
270
        m = "argmap unzip list: magic not found"
271
        raise ValueError(m)
272

    
273
    args = []
274
    append = args.append
275
    kw = OrderedDict()
276
    for k, v in argmap:
277
        if k is None:
278
            append(v)
279
        else:
280
            kw[k] = v
281
    return args, kw
282

    
283

    
284
def argmap_unzip(argmap):
285
    if hasattr(argmap, 'keys'):
286
        return argmap_unzip_dict(argmap)
287
    elif hasattr(argmap, '__iter__'):
288
        return argmap_unzip_list(argmap)
289
    else:
290
        m = "argmap: cannot unzip type %s" % (type(argmap),)
291
        raise ValueError(m)
292

    
293

    
294
def argmap_zip_list(args, kw):
295
    return [(None, a) for a in args] + kw.items() + [ARGMAP_MAGIC]
296

    
297

    
298
def argmap_zip_dict(args, kw):
299
    argmap = OrderedDict()
300
    argmap.update(kw)
301
    argmap[ARGMAP_MAGIC] = ARGMAP_MAGIC
302
    argmap[None] = list(args) + (argmap[None] if None in argmap else [])
303
    return argmap
304

    
305
argmap_zip = argmap_zip_list
306

    
307

    
308
def argmap_list_to_dict(argmap):
309
    args, kw = argmap_unzip_list(argmap)
310
    kw[ARGMAP_MAGIC] = ARGMAP_MAGIC
311
    kw[None] = args
312
    return kw
313

    
314

    
315
def argmap_dict_to_list(argmap):
316
    args, kw = argmap_unzip_dict(argmap)
317
    return args + kw.items() + [ARGMAP_MAGIC]
318

    
319

    
320
def argmap_unpack_list(argmap):
321
    kw = argmap_list_to_dict(argmap)
322
    if len(kw) == 2:
323
        return kw[None]
324
    return kw
325

    
326

    
327
def argmap_unpack_dict(argmap):
328
    if hasattr(argmap, 'keys') and callable(argmap.keys):
329
        return argmap_dict_to_list(argmap)[:-1]
330
    return argmap[:-1]