gpt4 book ai didi

python - "I/O operation on closed file"在 Django View 测试中使用 StringIO

转载 作者:太空宇宙 更新时间:2023-11-04 10:43:11 25 4
gpt4 key购买 nike

我继承了以下 Django View 代码,另一个 Web 服务使用它来提供输出数据的可下载版本:

def index(request):
# ... (snip) ...
data = base64.decodestring(request.POST['data'])
filename = request.POST['filename']

wrapper = FileWrapper(StringIO(data))

response = HttpResponse(wrapper, content_type=guess_type(str(filename))[0])

response['Content-Length'] = len(data)
response['Content-Disposition'] = "attachment; filename=" + filename

return response

函数本身——针对 Django 1.0 编写——在升级到 1.5 后仍然可以正常工作。不幸的是,涵盖此 View 的测试现在失败了:

    def testDownload(self):
self.client.login(username='test', password='test')

real = 'abc' * 100
data = base64.encodestring(real)
response = self.client.post("/api/v1/download/", {'data': data, 'filename': 'out.jpg'})

self.assertEqual(real, response.content)
self.assertEqual(response['Content-Disposition'], 'attachment; filename=out.jpg')

和错误:

Traceback (most recent call last):
File "/home/fred/.secret_projects/final/gerbils/tests/amf.py", line 548, in testDownload
self.assertEqual(real, response.content)
File "/home/fred/.virtualenvs/cunning_plot/lib/python2.7/site-packages/django/http/response.py", line 282, in content
self._consume_content()
File "/home/carl/.virtualenvs/cunning_plot/lib/python2.7/site-packages/django/http/response.py", line 278, in _consume_content
self.content = b''.join(self.make_bytes(e) for e in self._container)
File "/home/carl/.virtualenvs/cunning_plot/lib/python2.7/site-packages/django/http/response.py", line 278, in <genexpr>
self.content = b''.join(self.make_bytes(e) for e in self._container)
File "/usr/lib64/python2.7/wsgiref/util.py", line 30, in next
data = self.filelike.read(self.blksize)
File "/usr/lib64/python2.7/StringIO.py", line 127, in read
_complain_ifclosed(self.closed)
File "/usr/lib64/python2.7/StringIO.py", line 40, in _complain_ifclosed
raise ValueError, "I/O operation on closed file"
ValueError: I/O operation on closed file

所以..有什么想法吗?我在 testDownload()index() 中看不到任何必须在需要读取之前“关闭” StringIO 的内容。如果有的话,是不是也会影响到非考试的情况?

很迷茫。感谢帮助。

最佳答案

查看调用 close 的位置的一种简单方法是子类化 StringIO 并在 close 函数中放置一个断点。

class CustomStringIO(StringIO):
def close(self):
import pdb; pdb.set_trace()
super(CustomStringIO, self).close()

这个的堆栈是

-> response = self.client.post("/test/", {'data': data, 'filename': 'out.jpg'})
...\venv\lib\site-packages\django\test\client.py(463)post()
-> response = super(Client, self).post(path, data=data, content_type=content_type, **extra)
...\venv\lib\site-packages\django\test\client.py(297)post()
-> return self.request(**r)
...\venv\lib\site-packages\django\test\client.py(406)request()
-> response = self.handler(environ)
...\venv\lib\site-packages\django\test\client.py(119)__call__()
-> response.close() # will fire request_finished
...\venv\lib\site-packages\django\http\response.py(233)close()
-> closable.close()
> \testapp\views.py(11)close()
-> super(CustomStringIO, self).close()

看起来测试客户端正在关闭响应,它依次调用 FileWrapper 上的关闭,然后调用 StringIO 上的关闭。这一切都在您真正到达 response.content 之前。

您需要 FileWrapper 的原因是什么?由于 HttpResponse 接受字符串内容并且 base64.decodestring 返回一个二进制字符串,看来您可以将 data 直接传递给 HttpResponse 而不是必须创建 StringIOFileWrapper

关于python - "I/O operation on closed file"在 Django View 测试中使用 StringIO,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19279645/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com