1#!/usr/bin/env python 2 3r""" 4This module provides argument manipulation functions like pop_arg. 5""" 6 7import gen_print as gp 8import collections 9 10 11def pop_arg(default, *args, **kwargs): 12 r""" 13 Pop a named argument from the args/kwargs and return a tuple consisting of 14 the argument value, the modified args and the modified kwargs. 15 16 The name of the argument is determined automatically by this function by 17 examining the source code which calls it (see examples below). If no 18 suitable argument can be found, the default value passed to this function 19 will be returned as the argument value. This function is useful for 20 wrapper functions that wish to process arguments in some way before 21 calling subordinate function. 22 23 Examples: 24 25 Given this code: 26 27 def func1(*args, **kwargs): 28 29 last_name, args, kwargs = pop_arg('Doe', *args, **kwargs) 30 some_function(last_name.capitalize(), *args, **kwargs) 31 32 Consider this call to func1: 33 34 func1('Johnson', ssn='111-11-1111') 35 36 The pop_arg in func1 would return the following: 37 38 'Johnson', [], {'ssn': "111-11-1111"} 39 40 Notice that the 'args' value returned is an empty list. Since last_name 41 was assumed to be the first positional argument, it was popped from args. 42 43 Now consider this call to func1: 44 45 func1(last_name='Johnson', ssn='111-11-1111') 46 47 The pop_arg in func1 would return the same last_name value as in the 48 previous example. The only difference being that the last_name value was 49 popped from kwargs rather than from args. 50 51 Description of argument(s): 52 default The value to return if the named argument 53 is not present in args/kwargs. 54 args The positional arguments passed to the 55 calling function. 56 kwargs The keyword arguments passed to the 57 calling function. 58 """ 59 60 # Retrieve the argument name by examining the source code. 61 arg_name = gp.get_arg_name(None, arg_num=-3, stack_frame_ix=2) 62 if arg_name in kwargs: 63 arg_value = kwargs.pop(arg_name) 64 else: 65 # Convert args from a tuple to a list. 66 args = list(args) 67 if args: 68 arg_value = args.pop(0) 69 else: 70 arg_value = default 71 72 return arg_value, args, kwargs 73 74 75def source_to_object(value): 76 r""" 77 Evaluate string value as python source code and return the resulting 78 object. 79 80 If value is NOT a string or can not be interpreted as a python source 81 object definition, simply return value. 82 83 The idea is to convert python object definition source code (e.g. for 84 lists, dictionaries, tuples, etc.) into an object. 85 86 Example: 87 88 Note that this first example is a special case in that it is a short-cut 89 for specifying a collections.OrderedDict. 90 91 result = source_to_object("[('one', 1), ('two', 2), ('three', 3)]") 92 93 The result is a collections.OrderedDict object: 94 95 result: 96 [one]: 1 97 [two]: 2 98 [three]: 3 99 100 This is a short-cut for the long form shown here: 101 102 result = source_to_object("collections.OrderedDict([ 103 ('one', 1), 104 ('two', 2), 105 ('three', 3)])") 106 107 Also note that support for this special-case short-cut precludes the 108 possibility of interpreting such a string as a list of tuples. 109 110 Example: 111 112 In this example, the result will be a list: 113 114 result = source_to_object("[1, 2, 3]") 115 116 result: 117 result[0]: 1 118 result[1]: 2 119 result[2]: 3 120 121 Example: 122 123 In this example, the value passed to this function is not a string, so it 124 is simply returned. 125 126 result = source_to_object(1) 127 128 More examples: 129 result = source_to_object("dict(one=1, two=2, three=3)") 130 result = source_to_object("{'one':1, 'two':2, 'three':3}") 131 result = source_to_object(True) 132 etc. 133 134 Description of argument(s): 135 value If value is a string, it will be evaluated 136 as a python statement. If the statement 137 is valid, the resulting object will be 138 returned. In all other cases, the value 139 will simply be returned. 140 """ 141 142 if type(value) not in gp.get_string_types(): 143 return value 144 145 # Strip white space prior to attempting to interpret the string as python 146 # code. 147 value = value.strip() 148 149 # Try special case of collections.OrderedDict: 150 if value.startswith("["): 151 try: 152 return eval("collections.OrderedDict(" + value + ")") 153 except (TypeError, NameError, ValueError): 154 pass 155 156 try: 157 return eval(value) 158 except (NameError, SyntaxError): 159 pass 160 161 return value 162 163 164def args_to_objects(args): 165 r""" 166 Run source_to_object() on each element in args and return the result. 167 168 Description of argument(s): 169 args A type of dictionary, list, set, tuple or 170 simple object whose elements are to be 171 converted via a call to source_to_object(). 172 """ 173 174 type_of_dict = gp.is_dict(args) 175 if type_of_dict: 176 if type_of_dict == gp.dict_type(): 177 return {k: source_to_object(v) for (k, v) in args.items()} 178 elif type_of_dict == gp.ordered_dict_type(): 179 return collections.OrderedDict((k, v) for (k, v) in args.items()) 180 elif type_of_dict == gp.dot_dict_type(): 181 return DotDict((k, v) for (k, v) in args.items()) 182 elif type_of_dict == gp.normalized_dict_type(): 183 return NormalizedDict((k, v) for (k, v) in args.items()) 184 # Assume args is list, tuple or set. 185 if type(args) in (list, set): 186 return [source_to_object(arg) for arg in args] 187 elif type(args) is tuple: 188 return tuple([source_to_object(arg) for arg in args]) 189 190 return source_to_object(args) 191