[Django] #25576: HttpResponse can't be wrapped by io.TextIOWrapper; add required IOBase methods

16 views
Skip to first unread message

Django

unread,
Oct 20, 2015, 12:49:22 PM10/20/15
to django-...@googlegroups.com
#25576: HttpResponse can't be wrapped by io.TextIOWrapper; add required IOBase
methods
-------------------------------+--------------------
Reporter: jdufresne | Owner: nobody
Type: Bug | Status: new
Component: HTTP handling | Version: master
Severity: Normal | Keywords:
Triage Stage: Unreviewed | Has patch: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------+--------------------
In Python3, the stdlib CSV writer [1] is expected to write to a text file,
not a binary file. Observe writing to a bytes buffer:

{{{
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.

Django

unread,
Oct 20, 2015, 1:29:04 PM10/20/15
to django-...@googlegroups.com
#25576: HttpResponse can't be wrapped by io.TextIOWrapper; add required IOBase
methods
-------------------------------+------------------------------------
Reporter: jdufresne | Owner: nobody
Type: New feature | Status: new

Component: HTTP handling | Version: master
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0

Easy pickings: 0 | UI/UX: 0
-------------------------------+------------------------------------
Changes (by claudep):

* 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>

Django

unread,
Oct 20, 2015, 5:41:35 PM10/20/15
to django-...@googlegroups.com
#25576: HttpResponse can't be wrapped by io.TextIOWrapper; add required IOBase
methods
-------------------------------+------------------------------------
Reporter: jdufresne | Owner: nobody
Type: New feature | Status: new

Component: HTTP handling | Version: master
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0

Easy pickings: 0 | UI/UX: 0
-------------------------------+------------------------------------
Changes (by jdufresne):

* has_patch: 0 => 1


--
Ticket URL: <https://code.djangoproject.com/ticket/25576#comment:2>

Django

unread,
Oct 21, 2015, 3:15:11 AM10/21/15
to django-...@googlegroups.com
#25576: HttpResponse can't be wrapped by io.TextIOWrapper; add required IOBase
methods
-------------------------------------+-------------------------------------
Reporter: jdufresne | Owner: nobody
Type: New feature | Status: new

Component: HTTP handling | Version: master
Severity: Normal | Resolution:
Keywords: | Triage Stage: Ready for
| checkin

Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0

Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by claudep):

* stage: Accepted => Ready for checkin


--
Ticket URL: <https://code.djangoproject.com/ticket/25576#comment:3>

Django

unread,
Oct 21, 2015, 10:43:01 AM10/21/15
to django-...@googlegroups.com
#25576: HttpResponse can't be wrapped by io.TextIOWrapper; add required IOBase
methods
-------------------------------------+-------------------------------------
Reporter: jdufresne | Owner: nobody
Type: New feature | Status: closed

Component: HTTP handling | Version: master
Severity: Normal | Resolution: fixed

Keywords: | Triage Stage: Ready for
| checkin
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0

Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Tim Graham <timograham@…>):

* 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>

Reply all
Reply to author
Forward
0 new messages