Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flask test_client removes query string parameters

I am using Flask to create a couple of very simple services. From outside testing (using HTTPie) parameters through querystring are getting to the service.

But if I am using something like.

    data = {
        'param1': 'somevalue1',
        'param2': 'somevalue2'}

    response = self.client.get(url_for("api.my-service", **data))

I can see the correct URI being created:

http://localhost:5000/api1.0/my-service?param1=somevalue1&param2=somevalue2

when I breakpoint into the service:

request.args

is actually empty.

self.client is created by calling app.test_client() on my configured Flask application.

Anyone has any idea why anything after ? is being thrown away or how to work around it while still using test_client?

like image 966
Flaker Avatar asked Jan 20 '15 20:01

Flaker


2 Answers

I've just found out a workaround.

Make

data = {
    'param1': 'somevalue1',
    'param2': 'somevalue2'}

response = self.client.get(url_for("api.my-service", **data))

into this:

data = {
    'param1': 'somevalue1',
    'param2': 'somevalue2'}

response = self.client.get(url_for("api.my-service"), query_string = data)

This works but seems a bit unintuitive, and debugging there is a place where the provided query string in the URI is thrown away ....

But anyway this works for the moment.

like image 197
Flaker Avatar answered Oct 12 '22 10:10

Flaker


I know this is an old post, but I ran into this too. There's an open issue about this in the flask github repository. It appears this is intended behavior. From a response in the issue thread:

mitsuhiko commented on Jul 24, 2013
That's currently intended behavior. The first parameter to the test client should be a relative url. If it's not, then the parameters are removed as it's treated as if it was url joined with the second. This works:

>>> from flask import Flask, request
>>> app = Flask(__name__)
>>> app.testing = True
>>> @app.route('/')
... def index():
...  return request.url
... 
>>> c = app.test_client()
>>> c.get('/?foo=bar').data
'http://localhost/?foo=bar'

One way to convert your absolute url into a relative url and keep the query string is to use urlparse:

from urlparse import urlparse

absolute_url = "http://someurl.com/path/to/endpoint?q=test"
parsed = urlparse(absolute_url)
path = parsed[2] or "/"
query = parsed[4]
relative_url = "{}?{}".format(path, query)

print relative_url
like image 37
Troy Avatar answered Oct 12 '22 11:10

Troy