1

In my Flask app I am setting a number of local variables that have come in via an API call, using the

from flask import request
.
.
submission_id = request.args.get('submission_id')
grader = request.args.get('grader')
grading_factor = float(request.args.get('grading_factor'))
answer_key = request.args.get('answer_key')
submission_key = request.args.get('submission_key')

What is a less repetitive or otherwise more Pythonic way of setting these 5 variables?

3
  • 4
    Do you need them as separate variables? Commented May 31, 2016 at 7:56
  • 4
    I'd assign request.args.get to some getarg variable to get rid of the redundancy, but other than that this seems optimal. If you want something fancier and have many endpoints and plenty of time, you might write a decorator that maps request args to the view function arguments. Commented May 31, 2016 at 8:06
  • @bereal that sounds interesting ... are there any resources you can point me to for mapping request args to view function args? Commented May 31, 2016 at 8:54

3 Answers 3

2

As I suggested in the comments, you could come up with a decorator that would map the request arguments to the corresponding function parameters, such as:

def map_args(func):
    @functools.wraps(func)
    def wrapper(**kwargs):
        all_args = dict(request.args, **kwargs)
        return func(**all_args)

    return wrapper

Then:

@app.route('/mypath')
@map_args
def handler(submission_id, grader, grading_factor, ...):
    """the remaining logic"""

That's similar to what Flask does with the view_args, except that it does not do any type conversions, which this margin is too narrow to contain.

Sign up to request clarification or add additional context in comments.

Comments

2
from flask import Flask, request

app = Flask(__name__)

class DotDict(object):
    def __init__(self, inner):
        self._inner = inner

    def __getattr__(self, item):
        return self._inner.get(item)

    def get(self, item, default=None):
        return self._inner.get(item, default)

class LazyAttribute(object):
    def __init__(self, obj, attr):
        self.obj = obj
        self.attr = attr

    def __getattribute__(self, item):
        return getattr(getattr(object.__getattribute__(self, 'obj'),
                               object.__getattribute__(self, 'attr')),
                       item)

rargs = DotDict(LazyAttribute(request, 'args'))

@app.route("/")
def hello():
    print rargs.a, rargs.c, rargs.get('d', 3)
    return "Hello World!"

if __name__ == "__main__":
    app.run(debug=True)

Accessing http://localhost:5000/?a=1 prints 1 None 3 in the terminal.

The LazyAttribute class is because calling just DotDict(request.args) outside of a request context throws an error. The alternative is to make a function:

def rargs():
    return DotDict(request.args)

but I wanted to make usage as smooth as possible.

Comments

1

Firstly, I don't think there's anything wrong with the way you're doing it. But, there are a couple of different approaches you could take; the first being to the call to get the argument from request:

from flask import request

# ...

def getRequestArg(name, *args):
    return request.args.get(name, *args)

submission_id = getRequestArg('submission_id')
grader = getRequestArg('grader')
grading_factor = float(getRequestArg('grading_factor'))
answer_key = getRequestArg('answer_key')
submission_key = getRequestArg('submission_key')

If you don't need each of these to be separate local variables, you could store them all in a dict:

from flask import request

# ...

args = {}
arg_names = ('submission_id', 'grader', 'grading_factor', 'answer_key', 'submission_key')
for arg in arg_names:
    args[arg] = request.args.get(arg)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.