1e7e9171eSGeorge Keishing#!/usr/bin/env python3 20ff2eed2SMichael Walsh 30ff2eed2SMichael Walshr""" 40ff2eed2SMichael WalshThis module provides argument manipulation functions like pop_arg. 50ff2eed2SMichael Walsh""" 60ff2eed2SMichael Walsh 7e635ddc0SGeorge Keishingimport collections 85731818dSPatrick Williams 9*20f38712SPatrick Williamsimport gen_print as gp 10*20f38712SPatrick Williams 110ff2eed2SMichael Walsh 12eefa8d98SMichael Walshdef pop_arg(pop_arg_default=None, *args, **kwargs): 130ff2eed2SMichael Walsh r""" 14410b1787SMichael Walsh Pop a named argument from the args/kwargs and return a tuple consisting of the argument value, the 15410b1787SMichael Walsh modified args and the modified kwargs. 160ff2eed2SMichael Walsh 17410b1787SMichael Walsh The name of the argument is determined automatically by this function by examining the source code which 18410b1787SMichael Walsh calls it (see examples below). If no suitable argument can be found, the default value passed to this 19410b1787SMichael Walsh function will be returned as the argument value. This function is useful for wrapper functions that wish 20410b1787SMichael Walsh to process arguments in some way before calling subordinate function. 210ff2eed2SMichael Walsh 220ff2eed2SMichael Walsh Examples: 230ff2eed2SMichael Walsh 240ff2eed2SMichael Walsh Given this code: 250ff2eed2SMichael Walsh 260ff2eed2SMichael Walsh def func1(*args, **kwargs): 270ff2eed2SMichael Walsh 280ff2eed2SMichael Walsh last_name, args, kwargs = pop_arg('Doe', *args, **kwargs) 290ff2eed2SMichael Walsh some_function(last_name.capitalize(), *args, **kwargs) 300ff2eed2SMichael Walsh 310ff2eed2SMichael Walsh Consider this call to func1: 320ff2eed2SMichael Walsh 330ff2eed2SMichael Walsh func1('Johnson', ssn='111-11-1111') 340ff2eed2SMichael Walsh 350ff2eed2SMichael Walsh The pop_arg in func1 would return the following: 360ff2eed2SMichael Walsh 370ff2eed2SMichael Walsh 'Johnson', [], {'ssn': "111-11-1111"} 380ff2eed2SMichael Walsh 39410b1787SMichael Walsh Notice that the 'args' value returned is an empty list. Since last_name was assumed to be the first 40410b1787SMichael Walsh positional argument, it was popped from args. 410ff2eed2SMichael Walsh 420ff2eed2SMichael Walsh Now consider this call to func1: 430ff2eed2SMichael Walsh 440ff2eed2SMichael Walsh func1(last_name='Johnson', ssn='111-11-1111') 450ff2eed2SMichael Walsh 46410b1787SMichael Walsh The pop_arg in func1 would return the same last_name value as in the previous example. The only 47410b1787SMichael Walsh difference being that the last_name value was popped from kwargs rather than from args. 480ff2eed2SMichael Walsh 490ff2eed2SMichael Walsh Description of argument(s): 50eefa8d98SMichael Walsh pop_arg_default The value to return if the named argument is not present in args/kwargs. 51410b1787SMichael Walsh args The positional arguments passed to the calling function. 52410b1787SMichael Walsh kwargs The keyword arguments passed to the calling function. 530ff2eed2SMichael Walsh """ 540ff2eed2SMichael Walsh 550ff2eed2SMichael Walsh # Retrieve the argument name by examining the source code. 560ff2eed2SMichael Walsh arg_name = gp.get_arg_name(None, arg_num=-3, stack_frame_ix=2) 570ff2eed2SMichael Walsh if arg_name in kwargs: 580ff2eed2SMichael Walsh arg_value = kwargs.pop(arg_name) 590ff2eed2SMichael Walsh else: 600ff2eed2SMichael Walsh # Convert args from a tuple to a list. 610ff2eed2SMichael Walsh args = list(args) 620ff2eed2SMichael Walsh if args: 630ff2eed2SMichael Walsh arg_value = args.pop(0) 640ff2eed2SMichael Walsh else: 65eefa8d98SMichael Walsh arg_value = pop_arg_default 660ff2eed2SMichael Walsh 670ff2eed2SMichael Walsh return arg_value, args, kwargs 68c28deec7SMichael Walsh 69c28deec7SMichael Walsh 70c28deec7SMichael Walshdef source_to_object(value): 71c28deec7SMichael Walsh r""" 72410b1787SMichael Walsh Evaluate string value as python source code and return the resulting object. 73c28deec7SMichael Walsh 74410b1787SMichael Walsh If value is NOT a string or can not be interpreted as a python source object definition, simply return 75410b1787SMichael Walsh value. 76c28deec7SMichael Walsh 77410b1787SMichael Walsh The idea is to convert python object definition source code (e.g. for lists, dictionaries, tuples, etc.) 78410b1787SMichael Walsh into an object. 79c28deec7SMichael Walsh 80c28deec7SMichael Walsh Example: 81c28deec7SMichael Walsh 82410b1787SMichael Walsh Note that this first example is a special case in that it is a short-cut for specifying a 83410b1787SMichael Walsh collections.OrderedDict. 84c28deec7SMichael Walsh 85c28deec7SMichael Walsh result = source_to_object("[('one', 1), ('two', 2), ('three', 3)]") 86c28deec7SMichael Walsh 87c28deec7SMichael Walsh The result is a collections.OrderedDict object: 88c28deec7SMichael Walsh 89c28deec7SMichael Walsh result: 90c28deec7SMichael Walsh [one]: 1 91c28deec7SMichael Walsh [two]: 2 92c28deec7SMichael Walsh [three]: 3 93c28deec7SMichael Walsh 94c28deec7SMichael Walsh This is a short-cut for the long form shown here: 95c28deec7SMichael Walsh 96c28deec7SMichael Walsh result = source_to_object("collections.OrderedDict([ 97c28deec7SMichael Walsh ('one', 1), 98c28deec7SMichael Walsh ('two', 2), 99c28deec7SMichael Walsh ('three', 3)])") 100c28deec7SMichael Walsh 101410b1787SMichael Walsh Also note that support for this special-case short-cut precludes the possibility of interpreting such a 102410b1787SMichael Walsh string as a list of tuples. 103c28deec7SMichael Walsh 104c28deec7SMichael Walsh Example: 105c28deec7SMichael Walsh 106c28deec7SMichael Walsh In this example, the result will be a list: 107c28deec7SMichael Walsh 108c28deec7SMichael Walsh result = source_to_object("[1, 2, 3]") 109c28deec7SMichael Walsh 110c28deec7SMichael Walsh result: 111c28deec7SMichael Walsh result[0]: 1 112c28deec7SMichael Walsh result[1]: 2 113c28deec7SMichael Walsh result[2]: 3 114c28deec7SMichael Walsh 115c28deec7SMichael Walsh Example: 116c28deec7SMichael Walsh 117410b1787SMichael Walsh In this example, the value passed to this function is not a string, so it is simply returned. 118c28deec7SMichael Walsh 119c28deec7SMichael Walsh result = source_to_object(1) 120c28deec7SMichael Walsh 121c28deec7SMichael Walsh More examples: 122c28deec7SMichael Walsh result = source_to_object("dict(one=1, two=2, three=3)") 123c28deec7SMichael Walsh result = source_to_object("{'one':1, 'two':2, 'three':3}") 124c28deec7SMichael Walsh result = source_to_object(True) 125c28deec7SMichael Walsh etc. 126c28deec7SMichael Walsh 127c28deec7SMichael Walsh Description of argument(s): 128410b1787SMichael Walsh value If value is a string, it will be evaluated as a python statement. If the 129410b1787SMichael Walsh statement is valid, the resulting object will be returned. In all other 130410b1787SMichael Walsh cases, the value will simply be returned. 131c28deec7SMichael Walsh """ 132c28deec7SMichael Walsh 133c28deec7SMichael Walsh if type(value) not in gp.get_string_types(): 134c28deec7SMichael Walsh return value 135c28deec7SMichael Walsh 136410b1787SMichael Walsh # Strip white space prior to attempting to interpret the string as python code. 137c28deec7SMichael Walsh value = value.strip() 138c28deec7SMichael Walsh 139410b1787SMichael Walsh # Try special case of collections.OrderedDict which accepts a list of tuple pairs. 1403af6087cSMichael Walsh if value.startswith("[("): 141c28deec7SMichael Walsh try: 142c28deec7SMichael Walsh return eval("collections.OrderedDict(" + value + ")") 143c28deec7SMichael Walsh except (TypeError, NameError, ValueError): 144c28deec7SMichael Walsh pass 145c28deec7SMichael Walsh 146c28deec7SMichael Walsh try: 147c28deec7SMichael Walsh return eval(value) 148c28deec7SMichael Walsh except (NameError, SyntaxError): 149c28deec7SMichael Walsh pass 150c28deec7SMichael Walsh 151c28deec7SMichael Walsh return value 152c28deec7SMichael Walsh 153c28deec7SMichael Walsh 154c28deec7SMichael Walshdef args_to_objects(args): 155c28deec7SMichael Walsh r""" 156c28deec7SMichael Walsh Run source_to_object() on each element in args and return the result. 157c28deec7SMichael Walsh 158c28deec7SMichael Walsh Description of argument(s): 159410b1787SMichael Walsh args A type of dictionary, list, set, tuple or simple object whose elements 160410b1787SMichael Walsh are to be converted via a call to source_to_object(). 161c28deec7SMichael Walsh """ 162c28deec7SMichael Walsh 163c28deec7SMichael Walsh type_of_dict = gp.is_dict(args) 164c28deec7SMichael Walsh if type_of_dict: 165c28deec7SMichael Walsh if type_of_dict == gp.dict_type(): 166c28deec7SMichael Walsh return {k: source_to_object(v) for (k, v) in args.items()} 167c28deec7SMichael Walsh elif type_of_dict == gp.ordered_dict_type(): 168c28deec7SMichael Walsh return collections.OrderedDict((k, v) for (k, v) in args.items()) 169c28deec7SMichael Walsh elif type_of_dict == gp.dot_dict_type(): 170c28deec7SMichael Walsh return DotDict((k, v) for (k, v) in args.items()) 171c28deec7SMichael Walsh elif type_of_dict == gp.normalized_dict_type(): 172c28deec7SMichael Walsh return NormalizedDict((k, v) for (k, v) in args.items()) 173c28deec7SMichael Walsh # Assume args is list, tuple or set. 174c28deec7SMichael Walsh if type(args) in (list, set): 175c28deec7SMichael Walsh return [source_to_object(arg) for arg in args] 176c28deec7SMichael Walsh elif type(args) is tuple: 177c28deec7SMichael Walsh return tuple([source_to_object(arg) for arg in args]) 178c28deec7SMichael Walsh 179c28deec7SMichael Walsh return source_to_object(args) 180