0

I have the following function:

def request( url, type, headers, simulate = False, data = {}):

I want to be able to load the parameters from a text file and pass them to the function, I tried using evil eval below:

if execute_recovery:
    for command in content:
        logger.debug("Executing: "+command)
        try:
            result = eval(utilities.request("{0}").format(command))

            if not result["Success"]:
                continue_recovery = utilities.query_yes_no("Warning: Previous recovery command failed, attempt to continue recovery?\n")
                if not continue_recovery:
                    break
                else:
                    logger.debug("Command executed successfully...")
         except Exception, e:
             logger.debug( "Recovery: Eval Error, %s" % str(e) )

Where command would be a line in a text file like:

"http://192.168.1.1/accounts/1/users/1",delete,headers,simulate=False,data={}

This throws me the following error:

'request() takes at least 3 arguments (1 given)'

So presumably this means that it is interpreting the command as a single string instead of different parameters.

Does anybody know how to solve this?

TomSelleck
  • 6,706
  • 22
  • 82
  • 151
  • 1
    Possibly unrelated: But [don't use mutable objects as default argument value](http://stackoverflow.com/questions/1132941/least-astonishment-in-python-the-mutable-default-argument). – Ashwini Chaudhary Jul 03 '14 at 09:31
  • 1
    It would be better to have the arguments in some more 'friendly' format, like say json which can be safely loaded back into python objects. – Burhan Khalid Jul 03 '14 at 10:30
  • That's actually a very good idea @BurhanKhalid - I'll consider that - thanks! – TomSelleck Jul 03 '14 at 10:45

2 Answers2

1

I can't understand what you are trying to do there with eval or format. For one thing, you've put eval around the call to request itself, so it will evaluate the return value rather than call it with some dynamic value.

But you don't need eval at all. You just need to pass the arguments using the * and ** operators:

args = []
kwargs = {}
for arg in command.split(','):
    if '=' in arg:
        k, v = arg.split('=')
        kwargs[k] = ast.literal_eval(v)
    else:
        args.append(arg)
result = utilities.request(*args, **kwargs)
Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
  • If I have a case where the command would look like `"http://192.168.1.1/accounts/1/users/",post,headers,simulate=False,data={username:"john",age:"30"}`, would this solution still work? – TomSelleck Jul 03 '14 at 09:39
  • Hmm, probably not. You could use `ast.literal_eval` to convert the kwarg value in that case, see my edit. – Daniel Roseman Jul 03 '14 at 09:44
0

Using @BurhanKhalid's suggestion, I decided to store the parameters as a json object and load them at run time like so:

Store parameters here:

def request( url, type, headers, simulate = False, data = {}):
    if simulate:
        recovery_command = {"url":url, "type" : type, "data" : data}
        recovery.add_command(json.dumps(recovery_command))
        ...

Load parameters here:

def recovery():
...
    if execute_recovery:
        for command in content:
            logger.debug("Executing: "+command)
            try:

                recovery_command = json.loads(command)

                result = utilities.request(url = recovery_command["url"], type = recovery_command["type"], headers = headers, simulate = False, data = recovery_command["data"])

                if not result["Success"]:
                    continue_recovery = utilities.query_yes_no("Warning: Previous recovery command failed, attempt to continue recovery?\n")
                    if not continue_recovery:
                        break
                else:
                    logger.debug("Command executed successfully...")
            except Exception, e:
                logger.debug( "Recovery: Eval Error, %s" % str(e) )
TomSelleck
  • 6,706
  • 22
  • 82
  • 151