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