inconshreveable/sqltap — pull request #10 by homeworkprod (2014-09-23 02:14:17+00:00)
Title: Make on/off/clear actions work in WSGI middleware on Python 3.

I'm running sqltap 0.3.3 on Python 3.4.1 with Flask 0.10.1 and Werkzeug 0.9.6, using Werkzeug's built-in server (through Flask).

After injecting the WSGI middleware and pointing the browser to `/__sql__`, the toolbar appears.

Clicking on the "on" button results in a blank page and this stacktrace:
```pytb
127.0.0.1 - - [23/Sep/2014 03:11:41] "POST /__sqltap__ HTTP/1.1" 400 -
Error on request:
Traceback (most recent call last):
File "/home/user/someproject/venv/lib/python3.4/site-packages/werkzeug/serving.py", line 177, in run_wsgi
execute(self.server.app)
File "/home/user/someproject/venv/lib/python3.4/site-packages/werkzeug/serving.py", line 168, in execute
write(data)
File "/home/user/someproject/venv/lib/python3.4/site-packages/werkzeug/serving.py", line 148, in write
assert type(data) is bytes, 'applications must write bytes'
AssertionError: applications must write byte
```

Werkzeug on Python 3 wants byte strings, but gets unicode strings. After turning the error message string with the status code 400 into a byte string, it is shown instead of the blank page, stating that no expected value for the "turn" parameter was passed.
(This likely has to be done to the error message for status code 405 as well in order to display it when appropriate. The value returned from the `render_response` method, however, is fine, as it explicitly encodes to a byte string [return [html.encode('utf-8)]`].)

The processed form data, as assigned to the name `body`, consists of byte strings as well. After pressing the "on" button, it is represented by Python like this:
```python
{b'turn': [b'on']}
```
The values tested against it are unicode strings, though, so comparisons fail. Changing string literals into byte string literals makes the conditional logic work as expected.

I attached a patch so you can see what I did to get sqltap basically working. This might not catch every case on Python 3. And it probably won't work on Python 2. At the moment, I have no practical suggestion on how to modify the code to work on both Python 2 and 3. Maybe including a WSGI toolkit to abstract the code from these issues would make sense (with Werkzeug and its WSGI helpers being the obvious choice here).