func createEnviron(wr *Request) (py.Dict, error) {
	var d py.Dict
	if wsgiVersion.PyObject == nil {
		wv, err := py.NewTuple(2)
		if err != nil {
			return d, err
		} else if err := wv.SetItemInt(0, 1); err != nil {
			wv.DecRef()
			return d, err
		} else if err := wv.SetItemInt(1, 0); err != nil {
			wv.DecRef()
			return d, err
		}
		wsgiVersion = wv
	}
	d, err := py.NewDict()
	if err != nil {
		return d, err
	}
	sicscs(d, "REQUEST_METHOD", wr.req.Method)
	sicscs(d, "SCRIPT_NAME", "")
	sicss(d, "PATH_INFO", wr.req.URL.Path)
	sicss(d, "QUERY_STRING", wr.req.URL.RawQuery)
	sicss(d, "CONTENT_TYPE", wr.req.Header.Get("Content-Type"))
	sicss(d, "CONTENT_LENGTH", wr.req.Header.Get("Content-Length"))
	sicss(d, "SERVER_NAME", "127.0.0.1")
	sicss(d, "SERVER_PORT", "8080")
	sicss(d, "SERVER_PROTOCOL", wr.req.Proto)
	sicsi(d, "wsgi.version", wsgiVersion.Object)
	var scheme string
	if wr.req.TLS != nil {
		scheme = "https"
	} else {
		scheme = "http"
	}
	sicscs(d, "wsgi.url_scheme", scheme)
	sicsi(d, "wsgi.input", wr.wsgiInput)
	sicsi(d, "wsgi.errors", wr.wsgiErrors)
	sicsi(d, "wsgi.multithread", py.True)
	sicsi(d, "wsgi.multiprocess", py.True)
	sicsi(d, "wsgi.run_once", py.False)
	return d, nil
}
createEnviron returns a WSGI environ dict for the given request.
package wsgi
import (
	"net/http"
	"strconv"
	"strings"
	"github.com/noonat/whiskey/py"
	"github.com/pkg/errors"
)
var (
	pyCreateRequestObjects py.Object
	wsgiVersion            py.Tuple
	moduleSource = `
import _whiskey
__version__ = '0.1.0'
class ErrorsWriter(object):
    def __init__(self, index):
        self._index = index
    def flush(self):
        _whiskey.call("wsgi_errors_flush", (self._index,))
    def write(self, string):
        _whiskey.call("wsgi_errors_write", (self._index, string))
    def writelines(self, strings):
        for string in strings:
            _whiskey.call("wsgi_errors_write", (self._index, string))
class InputReader(object):
    def __init__(self, index):
        self._index = index
    def __iter__(self):
        return self
    def next(self):
        line = _whiskey.call("wsgi_input_read_line", (self._index, None))
        if line == '':
            raise StopIteration()
        return line
    def read(self, size=None):
        return _whiskey.call("wsgi_input_read", (self._index, size))
    def readline(self, size=None):
        return _whiskey.call("wsgi_input_read_line", (self._index, size))
    def readlines(self, sizehint=None):
        return list(self)
def create_request_objects(index):
    def start_response(status, headers, exc_info=None):
        return _whiskey.call("wsgi_start_response", (index, status, headers,
                                                     exc_info))
    return start_response, InputReader(index), ErrorsWriter(index)
`
)
func init() {
	py.AddInitializer(func() error {
		registerCallbacks()
		m, err := py.NewModuleString("whiskey", moduleSource)
		if err != nil {
			return err
		}
		defer m.DecRef()
		pyCreateRequestObjects, err = m.GetAttrString("create_request_objects")
		if err != nil {
			return err
		}
		return nil
	})
	py.AddFinalizer(func() error {
		if pyCreateRequestObjects.PyObject != nil {
			pyCreateRequestObjects.DecRef()
			pyCreateRequestObjects.PyObject = nil
		}
		return nil
	})
}
func loadApplication(moduleName, applicationName string) (py.Object, error) {
	m, err := py.ImportModule(moduleName)
	if err != nil {
		return py.Object{}, err
	}
	defer m.DecRef()
	application, err := m.GetAttrString(applicationName)
	if err != nil {
		return py.Object{}, err
	} else if !application.IsCallable() {
		application.DecRef()
		return py.Object{}, errors.New("application is not callable")
	}
	return application, nil
}
func callApplication(wr *Request) (py.Iter, error) {
	environ, err := createEnviron(wr)
	if err != nil {
		return py.Iter{}, err
	}
	response, err := wr.application.Call(environ.Object, wr.startResponse)
	if err != nil {
		return py.Iter{}, err
	}
	return response.Iter()
}
func writeResponse(wr *Request, iter py.Iter) error {
	wroteHeaders := false
	for {
		value, err := iter.Next()
		if err != nil {
			return err
		} else if value.PyObject == nil {
			break
		}
		s, err := value.GoString()
		value.DecRef()
		if err != nil {
			return err
		}
		b := []byte(s)
		if len(b) == 0 {
			continue
		}
		if !wroteHeaders {
			for k, vs := range wr.headers {
				for _, v := range vs {
					wr.w.Header().Add(k, v)
				}
			}
			wr.w.WriteHeader(wr.code)
			wroteHeaders = true
		}
		wr.w.Write(b)
	}
	return nil
}
func convertHeaders(wsgiHeaders py.List) (http.Header, error) {
	headers := http.Header{}
	length := wsgiHeaders.Len()
	for i := 0; i < length; i++ {
		h, err := wsgiHeaders.GetItem(i)
		if err != nil {
			return headers, err
		}
		ht, err := h.Tuple()
		if err != nil {
			return headers, err
		}
		var k, v string
		if err := ht.GetItems(&k, &v); err != nil {
			return headers, err
		}
		headers.Add(k, v)
	}
	return headers, nil
}
func convertStatus(status py.String) (int, error) {
	s, err := status.GoString()
	if err != nil {
		return 500, err
	}
	i := strings.IndexRune(s, ' ')
	if i == -1 {
		return 500, errors.New("invalid status string, couldn't find space character")
	}
	code, err := strconv.Atoi(s[:i])
	if err != nil {
		return 500, errors.Wrap(err, "error converting status to integer")
	}
	return code, nil
}
func createRequestObjects(index int) (startResponse, wsgiInput, wsgiErrors py.Object, err error) {
	pi, err := py.NewInt(index)
	if err != nil {
		return
	}
	defer pi.DecRef()
	r, err := pyCreateRequestObjects.Call(pi.Object)
	if err != nil {
		return
	}
	defer r.DecRef()
	rt, err := r.Tuple()
	if err != nil {
		return
	}
	items := [3]py.Object{}
	for i := 0; i < 3; i++ {
		items[i], err = rt.GetItem(i)
		if err != nil {
			return
		}
	}
	startResponse, wsgiInput, wsgiErrors = items[0], items[1], items[2]
	return
}
func sicscs(d py.Dict, k, v string) error {
	pk, err := py.CachedString(k)
	if err != nil {
		return err
	}
	pv, err := py.CachedString(v)
	if err != nil {
		return err
	}
	return d.SetItem(pk.Object, pv.Object)
}
func sicss(d py.Dict, k, v string) error {
	pk, err := py.CachedString(k)
	if err != nil {
		return err
	}
	return d.SetItemString(pk.Object, v)
}
func sicsi(d py.Dict, k string, v py.Object) error {
	pk, err := py.CachedString(k)
	if err != nil {
		return err
	}
	return d.SetItem(pk.Object, v)
}