0

I have the following request file that is called when running a wsgiref server:

import cgi, os
import cgitb; cgitb.enable() 
import pdb, time


STATUS_TEXT = \
  {
  200: 'OK',
  400: 'Bad Request',
  401: 'Unauthorized',
  403: 'Forbidden',
  404: 'Not Found',
  409: 'Conflict'
  }

class AmyTest( object ):

  def __init__( self, env, start_response ):
    """
rootDir_  is used to have the path just in case you need to refer to
    files in the directory where your script lives
environ_  is how most things are passed
startReponse_  is WSGI interface for communicating results
"""
    self.rootDir_ = os.environ.get( 'ROOT_DIR', ',' )
    self.environ_ = env
    self.startResponse_ = start_response

  def doTest( self ):

    method = self.environ_.get( 'REQUEST_METHOD', 'get' ).lower()
    if method == 'post':
      params = cgi.FieldStorage(
      fp = self.environ_[ 'wsgi.input' ],
          environ = self.environ_, keep_blank_values = True
      )
    else:
      params = cgi.FieldStorage(
          environ = self.environ_, keep_blank_values = True
      )

    vehicle_type = params.getfirst( 'vehicletype' )
    power_train_type = params.getfirst( 'powertraintype' )
    engine_displacement = params.getfirst( 'enginedisplacement' )
    engine_power = params.getfirst( 'enginepower' )
    curb_weight = params.getfirst( 'curbweight' )
    gv_weight = params.getfirst( 'gvweight' )
    frontal_area = params.getfirst( 'frontalarea' )
    coefficient_adrag = params.getfirst( 'coad' )
    rr_coefficient = params.getfirst( 'rrco' )
    sat_options = params.getfirst( 'satoptions' )

# This is the response HTML we are generating.
    fmt = """
<h2>Results</h2>
<table>
  <tr><td>Vehicle Type:</td><td>%s</td></tr>
  <tr><td>Power Train Type:</td><td>%s</td></tr>
  <tr><td>Engine Displacement (L):</td><td>%s</td></tr>
  <tr><td>Engine Power (hp):</td><td>%s</td></tr>
  <tr><td>Curb Weight (lbs):</td><td>%s</td></tr>
  <tr><td>Gross Vehicle Weight Rating (lbs):</td><td>%s</td></tr>
  <tr><td>Frontal Area (m^2):</td><td>%s</td></tr>
  <tr><td>Coefficient of Aerodynamic Drag:</td><td>%s</td></tr>
  <tr><td>Rolling Resistance Coefficient:</td><td>%s</td></tr>
  <tr><td>Selected Advanced Technology Options:</td><td>%s</td></tr>
</table>
"""
    content = fmt % ( vehicle_type, power_train_type, engine_displacement, engine_power, curb_weight, gv_weight, frontal_area, coefficient_adrag, rr_coefficient, sat_options)

    headers = \
      [
#        ( 'Content-disposition',
#          'inline; filename="%s.kmz"' % excat_in[ 'name' ] )
      ]

    result = \
      {
      'body': content,
      'code': 200,
      'headers': headers,
      'type': 'text/html'
      }
    time.sleep(5)
    return result


  def process( self ):
    result = self.doTest()
    return self.sendResponse( **result )

  def sendResponse( self, **kwargs ):
    """
@param  body
@param  code
@param  headers
@param  type
"""
    code = kwargs.get( 'code', 200 )
    status = '%d %s' % ( code, STATUS_TEXT[ code ] )

    body = kwargs.get( 'body', '' )
    mime_type = kwargs.get( 'type', 'text/plain' )
    headers = \
      [
        ( 'Content-Length', str( len( body ) ) ),
        ( 'Content-Type', mime_type )
      ]
    headers_in = kwargs.get( 'headers' )
    if headers_in != None and len( headers_in ) > 0:
      headers += headers_in

    self.startResponse_( status, headers )
    return [body]


  @staticmethod
  def processRequest( env, start_response ):
    server = AmyTest( env, start_response )
    return  server.process()

Everything works fine on Python 2 but when I try to run on Python 3 I get errors about write() argument must be bytes instance and NoneType object is not subscriptable. Errors from the console are:

Traceback (most recent call last):
  File "/Users/gavin/miniconda3/lib/python3.6/wsgiref/handlers.py", line 138, in run
    self.finish_response()
  File "/Users/gavin/miniconda3/lib/python3.6/wsgiref/handlers.py", line 180, in finish_response
    self.write(data)
  File "/Users/gavin/miniconda3/lib/python3.6/wsgiref/handlers.py", line 266, in write
    "write() argument must be a bytes instance"
AssertionError: write() argument must be a bytes instance

Traceback (most recent call last):
  File "/Users/gavin/miniconda3/lib/python3.6/wsgiref/handlers.py", line 141, in run
    self.handle_error()
  File "/Users/gavin/miniconda3/lib/python3.6/wsgiref/handlers.py", line 368, in handle_error
    self.finish_response()
  File "/Users/gavin/miniconda3/lib/python3.6/wsgiref/handlers.py", line 180, in finish_response
    self.write(data)
  File "/Users/gavin/miniconda3/lib/python3.6/wsgiref/handlers.py", line 274, in write
    self.send_headers()
  File "/Users/gavin/miniconda3/lib/python3.6/wsgiref/handlers.py", line 331, in send_headers
    if not self.origin_server or self.client_is_modern():
  File "/Users/gavin/miniconda3/lib/python3.6/wsgiref/handlers.py", line 344, in client_is_modern
    return self.environ['SERVER_PROTOCOL'].upper() != 'HTTP/0.9'
TypeError: 'NoneType' object is not subscriptable

Any suggestions on how to get this working in Python 3 would be very helpful.

wigging
  • 8,492
  • 12
  • 75
  • 117

1 Answers1

0

The write() function expecting bytes can be fixed by calling your_arg.encode(), if your_arg is a string. The encode() function converts a string to bytes, and decode() will convert bytes to a string.

The encode/decode functions are not available in python 3, converting bytes to strings and vice versa is handled differently in python 2.

The other error saying not subscriptable means it doesn't support subscript notation. E.g. foo[i]. So where you're getting that error, that object doesn't support [] subscripting.

Blaine Lafreniere
  • 3,451
  • 6
  • 33
  • 55
  • So where in my example code do I need to apply your suggestions? – wigging Jun 22 '17 at 02:06
  • The stacktrace will tell you. – Blaine Lafreniere Jun 22 '17 at 02:07
  • The error messages refer to `wsgiref` package. See my edited question for more details. I think the problem is the script I'm trying to run does not provide the correct types in Python 3. I just don't know where in my example code this is happening. – wigging Jun 22 '17 at 02:12
  • It sounds like the version of wsgiref that you're using isn't up to date with python 3, since the error occurs within the wsgiref library and not your code. – Blaine Lafreniere Jun 22 '17 at 02:16
  • as you said, it appears to be an issue with the version of wsgiref that was installed with Anaconda, thanks for the help – wigging Jun 22 '17 at 04:08