金字塔应用 "Header names must be latin1 string" 来自 WebTest 的 AssertionError

Pyramid app "Header names must be latin1 string" AssertionError from WebTest

当 Pyramid 应用程序 运行 in Python 2 和 from __future__ import unicode_literals 时,我如何处理来自 WebTest 的 "Header names must be latin1 string" AssertionError

我们正在将 Pyramid 应用程序从 Python 2 迁移到 3,并将 from __future__ import unicode_literals 添加到我们所有的 Python 文件,这导致了以下错误WebTest Python 2:

AssertionError: Header names must be latin1 string (not Py2 unicode or Py3 bytes type).

这里有一个 full traceback 以防有人感兴趣,尽管我认为它不是很有启发性。

只要您的应用设置任何响应 header,就会引发 AssertionError。例如,这一行会触发它:

response.headers["Access-Control-Allow-Origin"] = "*"

因为我们有 unicode_literals 这些字符串文字在 Python 2 中是 unicode 字符串,而在 unicode_literals 之前它们应该是字节字符串,这就是添加 unicode_literals 触发的原因来自 WebTest 的 AssertionError

在Python3中没有出现错误。

WebTest 有此 AssertionError 的原因是 https://www.python.org/dev/peps/pep-3333 要求 HTTP 响应 headers 是本机字符串 - Python 2 中的字节字符串和 Python 中的 unicode 字符串 Python 3. 这是添加断言的 WebTest 问题和拉取请求:

https://github.com/Pylons/webtest/issues/119
https://github.com/Pylons/webtest/pull/180

b - 像 response.headers[b"Access-Control-Allow-Origin"] = b"*" 这样的字符串前缀将摆脱 Python 2 中的 AssertionError 但如果测试是 [=67 则导致错误出现=] 在 Python 3.

response.headers[str("Access-Control-Allow-Origin")] = str("*") 一样将 str() 中的字符串换行将在 Python 2 和 3 中修复它,但需要您找到并 str()-换行每个响应 header 整个应用中的字符串。

添加一个 str()-包装所有响应 headers 的补间似乎是一个很好的解决方法:

def encode_headers_tween_factory(handler, registry):
    def encode_headers_tween(request):
        resp = handler(request)
        for key in resp.headers.keys():
            values = resp.headers.getall(key)
            del resp.headers[key]
            for value in values:
                resp.headers.add(str(key), str(value))
        return resp
    return encode_headers_tween

config.add_tween('h.tweens.encode_headers_tween_factory')

一旦您不再需要支持,您可以简单地删除这个补间 Python 2.