Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeError: sequence of byte string values expected, value of type str found

I'm trying to run a simple "hello world" application using mod_wsgi for Python 3. I'm using Fedora 23. Here's my Apache virtual host configuration:

<VirtualHost *:80>
    ServerName localhost
    ServerAdmin admin@localhost
    # ServerAlias foo.localhost
    WSGIScriptAlias /headers /home/httpd/localhost/python/headers/wsgi.py
    DocumentRoot /home/httpd/localhost/public_html
    ErrorLog /home/httpd/localhost/error.log
    CustomLog /home/httpd/localhost/requests.log combined
</VirtualHost>

wsgi.py:

def application(environ, start_response):
    status = '200 OK'
    output = 'Hello World!'

    response_headers = [('Content-Type', 'text/plain'),
                        ('Content-Length', str(len(output)))]

    start_response(status, response_headers)

    return [output]

It works fine if I use mod_wsgi for Python 2 (sudo dnf remove python3-mod_wsgi -y && sudo dnf install mod_wsgi -y && sudo apachectl restart), but I get a 500 internal server error when using Python 3. Here's the error log:

mod_wsgi (pid=899): Exception occurred processing WSGI script '/home/httpd/localhost/python/headers/wsgi.py'.
TypeError: sequence of byte string values expected, value of type str found

Update

Using encode() (or encode('utf-8')) on str(len(output)) isn't working either. Now I get:

Traceback (most recent call last):
  File "/home/httpd/localhost/python/headers/wsgi.py", line 8, in application
    start_response(status, response_headers)
TypeError: expected unicode object, value of type bytes found
like image 730
Sumit Avatar asked Jan 17 '16 12:01

Sumit


2 Answers

Apparently the variable output itself needs to have a bytes string rather than a unicode string. And it needs to change not only for response_headers, but for everywhere output is used (so str(len(output)).encode('utf-8') on line 6 wouldn't work, like I'd been trying).

So the solution in my case is:

def application(environ, start_response):
    status = '200 OK'
    output = b'Hello World!'

    response_headers = [('Content-type', 'text/plain'),
                        ('Content-Length', str(len(output)))]
    start_response(status, response_headers)

    return [output]

(which I found in one of the tests on the official mod_wsgi repo, as suggested by Rolbrok in comments.)

like image 168
Sumit Avatar answered Oct 15 '22 00:10

Sumit


Background

The issue is caused because Python 3 defaulted UTF-8, because today, we find that there is a lot of non native English characters, and it is best to accommodate them. HTTP works only with ASCII characters. It does not handle UTF-8 well. Hence, neither Apache,nor mod_wsgi works well with UTF 8.

Solution

So, after you prepare the entire html string, you can typecast it using the inbuilt python function - bytes(). This takes a string and gives a byte string.

Sample Code

html = "This "
html += "is the code"
html = bytes(html, encoding= 'utf-8')
response_header = [('Content-type', 'text/html')]
start_response(status, response_header)
yield html
like image 14
Rahul Avatar answered Oct 14 '22 23:10

Rahul