Statistics
| Branch: | Tag: | Revision:

root / commissioning / hlapi / util.py @ de34ce75

History | View | Annotate | Download (12.9 kB)

1
import sys
2

    
3
def isstr(s):
4
    return issubclass(type(s), basestring)
5

    
6
def compatible_type(given_t, expected_t):
7
    if issubclass(expected_t, basestring):
8
        expected_t = basestring
9
    if issubclass(given_t, basestring):
10
        given_t = basestring
11
    return given_t == expected_t
12
        
13

    
14
def compatible_input_types(given, expected):
15
#    print "given=%s, expected=%s" % (given, expected)
16
    if len(given) != len(expected):
17
        return False    
18
    for i in xrange(len(given)):
19
        if not compatible_type(given[i], expected[i]):
20
            return False
21
    return True
22

    
23

    
24
def compatible_return_type(given, expected):
25
    return compatible_type(given, expected)
26

    
27

    
28
def method_accepts(*types):
29
    '''Method decorator. Checks decorated function's arguments are
30
    of the expected types. The self argument is ignored. This is
31
    based on the ``accepts`` decorator.
32

33
    Parameters:
34
    types -- The expected types of the inputs to the decorated function.
35
             Must specify type for each parameter.
36
    '''
37
    try:
38
        def decorator(f):
39
            def newf(*args):
40
                args_to_check = args[1:] # Throw away self (or cls)
41
                assert len(args_to_check) == len(types)
42
                if len(args_to_check) != len(types):
43
                    raise TypeError("Wrong number of arguments. Expected is %s, given is %s" % (len(types), len(args_to_check)))
44
                argtypes = tuple(map(type, args_to_check))
45
#                if argtypes != types:
46
                if not compatible_input_types(argtypes, types):
47
                    msg = info(f.__name__, types, argtypes, 0)
48
                    raise TypeError, msg
49
                return f(*args)
50
            newf.__name__ = f.__name__
51
            return newf
52
        return decorator
53
    except KeyError, key:
54
        raise KeyError, key + "is not a valid keyword argument"
55
    except TypeError, msg:
56
        raise TypeError, msg
57

    
58
# http://wiki.python.org/moin/PythonDecoratorLibrary#Type_Enforcement_.28accepts.2Freturns.29
59
# Slightly modified to always raise an error
60
def accepts(*types):
61
    '''Function decorator. Checks decorated function's arguments are
62
    of the expected types.
63

64
    Parameters:
65
    types -- The expected types of the inputs to the decorated function.
66
             Must specify type for each parameter.
67
    '''
68
    try:
69
        def decorator(f):
70
            def newf(*args):
71
                if len(args) != len(types):
72
                    raise TypeError("Wrong number of arguments. Expected is %s, given is %s" % (len(types), len(args)))
73
                argtypes = tuple(map(type, args))
74
#                if argtypes != types:
75
                if not compatible_input_types(argtypes, types):
76
                    msg = info(f.__name__, types, argtypes, 0)
77
                    raise TypeError, msg
78
                return f(*args)
79
            newf.__name__ = f.__name__
80
            return newf
81
        return decorator
82
    except KeyError, key:
83
        raise KeyError, key + "is not a valid keyword argument"
84
    except TypeError, msg:
85
        raise TypeError, msg
86

    
87
# http://wiki.python.org/moin/PythonDecoratorLibrary#Type_Enforcement_.28accepts.2Freturns.29
88
# Slightly modified to always raise an error
89
def returns(ret_type):
90
    '''Function decorator. Checks decorated function's return value
91
    is of the expected type.
92

93
    Parameters:
94
    ret_type -- The expected type of the decorated function's return value.
95
                Must specify type for each parameter.
96
    '''
97
    try:
98
        def decorator(f):
99
            def newf(*args):
100
                result = f(*args)
101
                res_type = type(result)
102
                print "ret_type=%s, res_type=%s" % (ret_type, res_type)
103
#                if res_type != ret_type:
104
                if not compatible_type(res_type, ret_type):
105
                    msg = info(f.__name__, (ret_type,), (res_type,), 1)
106
                    raise TypeError, msg
107
                return result
108
            newf.__name__ = f.__name__
109
            return newf
110
        return decorator
111
    except KeyError, key:
112
        raise KeyError, key + "is not a valid keyword argument"
113
    except TypeError, msg:
114
        raise TypeError, msg
115

    
116

    
117
# http://wiki.python.org/moin/PythonDecoratorLibrary#Type_Enforcement_.28accepts.2Freturns.29
118
def info(fname, expected, actual, flag):
119
    '''Convenience function returns nicely formatted error/warning msg.'''
120
    format = lambda types: ', '.join([str(t).split("'")[1] for t in types])
121
    expected, actual = format(expected), format(actual)
122
    msg = "'{0}' method ".format( fname )\
123
          + ("accepts", "returns")[flag] + " ({0}), but ".format(expected)\
124
          + ("was given", "result is")[flag] + " ({0})".format(actual)
125
    return msg
126

    
127

    
128
def check_string(label, value):
129
    if not issubclass(type(value), basestring):
130
        raise Exception(
131
            "%s is not a string, but a(n) %s with value %s" % (
132
                label, type(value), value))
133
    return value
134

    
135

    
136
def check_context(context):
137
    assert isinstance(context, dict)
138
    return context
139

    
140

    
141
@accepts(str, str)
142
@returns(bool)
143
def is_abs_name(name, label='name'):
144
    check_string(label, name)
145
    return (name == 'system') or name.startswith('system/') 
146
    
147
    
148
def check_abs_name(abs_name, label = 'abs_name'):
149
    check_string(label, abs_name)
150
    if len(abs_name) == 0:
151
        raise Exception("Absolute %s is empty" % (label,))
152
    
153
    if abs_name.startswith('/'):
154
        raise Exception(
155
            "Absolute %s='%s' starts with '/'" % (label, abs_name))
156
        
157
    if abs_name.endswith('/'):
158
        raise Exception(
159
            "Absolute %s='%s' ends with '/'" % (label, abs_name))
160

    
161
    if (abs_name != 'system') and (not abs_name.startswith('system/')):
162
        raise Exception(
163
            "Unknown hierarchy for %s='%s'. Should be 'system' or start with 'system/'" % (
164
                label, abs_name))
165

    
166
    if abs_name.find('//') >= 0:
167
        raise Exception("// is not allowed in %s='%s'" % (
168
                label, abs_name))
169
         
170
    return abs_name
171

    
172
def check_relative_name(relative_name, label='relative_name'):
173
    check_string(label, relative_name)
174
    if relative_name.startswith('system') or relative_name.startswith('system/'):
175
        raise Exception("%s (='%s'), which was intended as relative, has absolute form" % (label, relative_name))
176
            
177
    return relative_name
178

    
179
def check_name(name, label='name'):
180
    check_string(label, name)
181
    if len(name) == 0:
182
        raise Exception("Name %s is empty" % (label,))
183
    
184
    if name.find('//') >= 0:
185
        raise Exception("// is not allowed in %s (='%s')" % (
186
                label, name))
187
        
188
    return name
189

    
190

    
191
def check_abs_global_resource_name(abs_resource_name,
192
                                   label='abs_resource_name'):
193
    """
194
    ``abs_resource_name`` must always be a string in absolute form.
195
    """
196
    check_abs_name(abs_resource_name, label)
197
    if not abs_resource_name.startswith(NameOfResourcesNode):
198
        raise Exception("'%s' is not a global resource name" % (abs_resource_name,))
199
        
200
    return abs_resource_name
201

    
202

    
203
def check_node_key(node_key):
204
    if node_key is not None:
205
        check_string('node_key', node_key)
206
    return node_key
207

    
208

    
209
def is_system_node(node_name):
210
    check_string('node_name', node_name)
211
    return node_name == 'system'
212

    
213

    
214
def level_of_node(node_name):
215
    """
216
    Returns the level of a node in the absolute hierarchy, that is under
217
    node 'system'.
218
    
219
    By convention, 'system' has level zero.
220
    """
221
    check_abs_name(node_name, 'node_name')
222
    len(node_name.split('/')) - 1
223
    
224

    
225
@accepts(str, str)
226
@returns(bool)
227
def is_child_of_abs_name(child, parent):
228
    check_abs_name(parent)
229
    return child.startswith(parent) and child != parent
230

    
231

    
232
def parent_abs_name_of(abs_name, label='abs_name'):
233
    """
234
    Given an absolute name, it returns its parent.
235
    If ``abs_name`` is 'system' then it returns 'system', since this is
236
    the convention of Quota Holder.
237
    """
238
    if is_system_node(abs_name):
239
        return abs_name
240
    else:
241
        check_abs_name(abs_name, label)
242

    
243
        # For 'a/b/c' we get ['a', 'b', 'c']
244
        # And for 'a' we get ['a']
245
        elements = abs_name.split('/')
246
        
247
        if len(elements) == 1:
248
            # This must be normally caught by the call check_abs_name(abs_name)
249
            # but let's be safe anyway 
250
            raise Exception(
251
                "Only 'system' is the top level entity, you provided '%s'" % (
252
                    abs_name))
253
        else:
254
            upto_name = '/'.join(elements[:-1])
255
            return upto_name
256

    
257

    
258
@accepts(str)
259
@returns(str)
260
def last_part_of_abs_name(abs_name, label='abs_name'):
261
    """
262
    Given an absolute abs_name, which is made of simple parts separated with
263
    slashes), computes the last part, that is the one after the last
264
    slash.
265
    """
266
    check_abs_name(abs_name, label)
267
    last_part = abs_name.split('/')[-1:]
268
    return last_part
269

    
270

    
271
@accepts(str, str, str, str)
272
@returns(str)
273
def reparent_child_name_under(child_name,
274
                              parent_node_name,
275
                              child_label='child_name',
276
                              parent_label='parent_node_name'):
277
    """
278
    Given a child name and an absolute parent node name, creates an
279
    absolute name for the child so as to reside under the given parent.
280
    """
281
    check_abs_name(parent_node_name, parent_label)
282

    
283
    if child_name == parent_node_name:
284
        raise Exception(
285
            "%s is the same as %s (='%s')" % (
286
                child_label,
287
                parent_label,
288
                parent_node_name)) 
289

    
290
    # If already under this parent, we are set.
291
    if child_name.startswith(parent_node_name):
292
        return child_name
293
    
294
    # Else, just make the new absolute name by concatenation
295
    return '%s/%s' % (parent_node_name, child_name)
296

    
297

    
298
def make_abs_group_name(group_name):
299
    check_name(group_name, 'group_name')
300
    return reparent_child_name_under(child_name=group_name,
301
                                     parent_node_name=NameOfGroupsNode,
302
                                     child_label='group_name',
303
                                     parent_label='NameOfGroupsNode')
304

    
305
def make_abs_global_resource_name(global_resource_name):
306
    check_name(global_resource_name, 'global_resource_name')
307
    return reparent_child_name_under(child_name=global_resource_name,
308
                                     parent_node_name=NameOfResourcesNode,
309
                                     child_label='global_resource_name',
310
                                     parent_label='NameOfResourcesNode') 
311

    
312
def make_abs_user_name(user_name):
313
    check_name(user_name, 'user_name')
314
    return reparent_child_name_under(child_name=user_name,
315
                                     parent_node_name=NameOfUsersNode,
316
                                     child_label='user_name',
317
                                     parent_label='NameOfUsersNode')
318

    
319

    
320
@accepts(str, str, str, str)
321
@returns(str)
322
def relative_child_name_under(child_name,
323
                              parent_name,
324
                              child_label='child_name',
325
                              parent_label='parent_name'):
326
    check_abs_name(parent_name, parent_label)
327
    
328
    if child_name == parent_name:
329
        raise Exception(
330
            "%s is the same as %s (='%s')" % (
331
                child_label,
332
                parent_label,
333
                parent_name)) 
334

    
335
    if not child_name.startswith(parent_name):
336
        raise Exception(
337
            "%s (='%s') is not a child of %s (='%s')" % (
338
                child_label,
339
                child_name,
340
                parent_label,
341
                parent_name))
342

    
343
    return child_name[len(parent_name) + 1:]
344

    
345

    
346
@accepts(str, str)
347
@returns(str)
348
def make_rel_group_name(group_name, label='group_name'):
349
    check_name(group_name, label)
350
    return relative_child_name_under(child_name=group_name,
351
                                     parent_name=NameOfGroupsNode,
352
                                     child_label='group_name',
353
                                     parent_label='NameOfGroupsNode')
354
    
355

    
356
@accepts(str, str)
357
@returns(str)
358
def make_rel_global_resource_name(resource_name, label='resource_name'):
359
    check_name(resource_name, label)
360
    return relative_child_name_under(child_name=resource_name,
361
                                     parent_name=NameOfResourcesNode,
362
                                     child_label='resource_name',
363
                                     parent_label='NameOfResourcesNode')
364
    
365

    
366
@accepts(str, str)
367
@returns(str)
368
def make_rel_user_name(user_name, label='user_name'):
369
    check_name(user_name, label)
370
    return relative_child_name_under(child_name=user_name,
371
                                     parent_name=NameOfUsersNode,
372
                                     child_label='user_name',
373
                                     parent_label='NameOfUsersNode')
374

    
375

    
376
NameOfSystemNode = 'system'
377
NameOfResourcesNode = 'system/resources'
378
NameOfGroupsNode = 'system/groups'
379
NameOfUsersNode = 'system/users'
380

    
381

    
382
ResourceAttributePrefixes = {
383
    NameOfResourcesNode: 'r',
384
    NameOfGroupsNode: 'g',
385
    NameOfUsersNode: 'u'
386
}
387