Search code examples
pythonparsingquery-stringfastcgiwsgi

Python: Breaking query string into associative array not working


This is a Python script to parse values from a query string.

The block inside app function works fine, when placed in a standalone Python script. But when placed in the app() function the values for temperature, humidity, wind and time are empty and that's wrong.

environ['QUERY_STRING'] can be "temperature=20&humidity=50&wind=30&time=morning"

This doesn't work:

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

import sys, os
from flup.server.fcgi import WSGIServer

import urlparse
import cgi

def app(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])

    qs = environ['QUERY_STRING'] # EQUALS temperature=20&humidity=50&wind=30&time=morning
    parsed = cgi.parse_qs(qs) # tried both cgi and urlparse

    yield parsed['temperature']
    yield parsed['humidity']
    yield parsed['wind']
    yield parsed['time']

WSGIServer(app).run()

Error:

/usr/local/lib/python2.7/site-packages/flup/server/fcgi_base.py in write(data=['20'])
   1062 
   1063         def write(data):
=> 1064             assert type(data) is str, 'write() argument must be string'
   1065             assert headers_set, 'write() before start_response()'
   1066 

This works:

qs = "temperature=20&humidity=50&wind=30&time=morning"
parsed = cgi.parse_qs(qs)
print parsed['temperature']
print parsed['humidity']
print parsed['wind']
print parsed['time']

Output:

['20']
['50']
['30']
['morning']

Solution

  • Yes, the return value of app() should be an iterable. I'm no WSGI expert so I've checked the fcgi source code to make sure.

    Try it like this:

    for k in ('temperature', 'humidity', 'wind', 'time'):
        yield parsed[k]
    

    If each value is actually a list of values and you just want the first, as alluded to above, do it like this:

    for k in ('temperature', 'humidity', 'wind', 'time'):
        yield parsed[k][0]
    

    I have edited my answer because I said earlier that it was not ok to have multiple yields outside a loop.. I researched it and that was an incorrect statement on my part. It is ok.. this is just a bit neater.

    Or just return them as a simple list or tuple since the values are in memory already and are quite small. The yield does not really buy you anything here.