{{{
import io
import csv
b = io.BytesIO()
w = csv.writer(b)
w.writerow(['a', 'b', 'c'])
}}}
{{{
Traceback (most recent call last):
File "test.py", line 8, in <module>
w.writerow(['a', 'b', 'c'])
TypeError: 'str' does not support the buffer interface
}}}
To handle this, one should use the stdlib's {{{io.TextIOWrapper}}} [2]:
{{{
import io
import csv
b = io.BytesIO()
wrapper = io.TextIOWrapper(b, 'utf-8', newline='')
w = csv.writer(wrapper)
w.writerow(['a', 'b', 'c'])
wrapper.flush()
print(b.getvalue())
}}}
{{{
b'a,b,c\r\n'
}}}
As Django's HttpResponse uses a binary file-like interface, I'd expect the
same to work. That is, wrap the response in a {{{io.TextIOWrapper}}} and
write the CSV document to the wrapper. However, this fails:
{{{
import io
import csv
from django.http.response import HttpResponse
r = HttpResponse()
wrapper = io.TextIOWrapper(r, 'utf-8', newline='')
w = csv.writer(wrapper)
w.writerow(['a', 'b', 'c'])
wrapper.flush()
print(r)
}}}
{{{
Traceback (most recent call last):
File "/home/jon/test.py", line 8, in <module>
wrapper = io.TextIOWrapper(r, 'utf-8')
AttributeError: 'HttpResponse' object has no attribute 'readable'
}}}
As HttpResponse is a binary file-like interface, I'm suggesting the
necessary methods/members be added so that it can be wrapped by
{{{io.TextIOWrapper}}}. These methods/members are documented in
io.BaseIO() [3]. From initial testing, only {{{readable()}}} and
{{{seekable()}}} are required for my use case.
This will make it easier to integrate text-only file interfaces to the
binary nature of the response.
[1] https://docs.python.org/3/library/csv.html#csv.writer
[2] https://docs.python.org/3/library/io.html#io.TextIOWrapper
[3] https://docs.python.org/3/library/io.html#io.IOBase
--
Ticket URL: <https://code.djangoproject.com/ticket/25576>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
* needs_better_patch: => 0
* stage: Unreviewed => Accepted
* type: Bug => New feature
* needs_tests: => 0
* needs_docs: => 0
Comment:
+1 (in the same spirit as #18523).
--
Ticket URL: <https://code.djangoproject.com/ticket/25576#comment:1>
* has_patch: 0 => 1
--
Ticket URL: <https://code.djangoproject.com/ticket/25576#comment:2>
* stage: Accepted => Ready for checkin
--
Ticket URL: <https://code.djangoproject.com/ticket/25576#comment:3>
* status: new => closed
* resolution: => fixed
Comment:
In [changeset:"05248a1009c05985b1c227a1a48b871c3068cb12" 05248a10]:
{{{
#!CommitTicketReference repository=""
revision="05248a1009c05985b1c227a1a48b871c3068cb12"
Fixed #25576 -- Added IOBase methods required by TextIOWrapper to
HttpResponse.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/25576#comment:4>