1

When trying to download the exported data via CSV, the terminal is coming back with an error. It is not a simple x.read() versus x.open() issue as shown here on a similar stacks question, but rather trickier since it's writing and saving to a csv file via Pyramid and Pyramid's Response method.

I am a bit confused as to why this is happening and could use some guidance on finding the bug. I appreciate the guidance and suggestions.

Python 2.7, Pyramid


View Code:

def export_results(request):
    response = Response(content_type='application/csv')
    results =  api.retrieve_assessment_results() #list retrieval of all results from db e.g. [<class(element, element)>, <class2(element, element)> ...]

    with NamedTemporaryFile(prefix='Export_%s' % datetime.now(),
        suffix='.csv', delete=True) as f:

        fileWriter = csv.writer(f, delimiter=',',quotechar='|', quoting=csv.QUOTE_MINIMAL)

        for a in results:
            print(a)
            fileWriter.writerow(['a.owner', 'a.assessment'])

        response.app_iter = f 
        response.headers['content_disposition'] = ('attachment; filename=Export.csv')

        return response

@view_config(route_name='analyst_view', renderer='templates/analyst_page.jinja2', request_method='GET', permission='read')
def analyst_view(request):
    #some other code 
    export = export_results(request)

    return {#other code, 'export': export}

Terminal Error:

 "/usr/local/lib/python2.7/site-packages/pyramid-1.5.7-py2.7.egg/pyramid/renderers.py", line 447, in render
    result = renderer(value, system_values)
  File "/usr/local/lib/python2.7/site-packages/pyramid_jinja2-2.5-py2.7.egg/pyramid_jinja2/__init__.py", line 265, in __call__
    return template.render(system)
  File "/usr/local/lib/python2.7/site-packages/jinja2/environment.py", line 969, in render
    return self.environment.handle_exception(exc_info, True)
  File "/usr/local/lib/python2.7/site-packages/jinja2/environment.py", line 742, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/Users/ack/code/venv/WEB/web/templates/analyst_page.jinja2", line 76, in top-level template code
    <div class="thumbnail"> <a href="{{export}}"><img src="{{request.static_url('web:static/img/book_bw.png')}}" width="2000" class="cards"/></a>
  File "build/bdist.macosx-10.10-x86_64/egg/webob/response.py", line 230, in __str__
    self.body
  File "build/bdist.macosx-10.10-x86_64/egg/webob/response.py", line 345, in _body__get
    body = b''.join(app_iter)
ValueError: I/O operation on closed file
Community
  • 1
  • 1
thesayhey
  • 938
  • 3
  • 17
  • 38

1 Answers1

3

By returning the response from a with block, you are closing the NamedTemporaryFile before it is returned. You don't want to write to a file, but to a stream.

I use something like the code below in Python3/Pyramid/SQLAlchemy and that works for me. Don't have python 2 installed, so not tested for python 2

import StringIO

f = StringIO.StringIO()

fileWriter = csv.writer(f, delimiter=',',quotechar='|',quoting=csv.QUOTE_MINIMAL)

for a in results:
    print(a)
    fileWriter.writerow(['a.owner', 'a.assessment'])

#rewind file
f.seek(0)
response = Response(
    request=request,
    content_disposition='attachment; filename="filename.csv"')
)
response.app_iter = f

return response
Thijs D
  • 762
  • 5
  • 20
  • I get an error: `File "/Users/ack/code/venv/WEB/web/views/default.py", line 104, in analyst_view export = export_results(request) File "/Users/ack/code/venv/WEB/nweb/views/default.py", line 83, in export_results fileWriter.writerow([a.owner, a.assessment]) TypeError: unicode argument expected, got 'str'` – thesayhey Feb 29 '16 at 20:41
  • 1
    I see now you are on Python 2.7, so the syntax is a bit different also. If that doesn't work, check [this question](http://stackoverflow.com/questions/13120127/how-can-i-use-io-stringio-with-the-csv-module). And maybe think of upgrading to python 3 ;) – Thijs D Feb 29 '16 at 20:48
  • For some reason, this is causing the export button to a 404 Not Found error: `404 Not Found The resource could not be found. /users/200 OKContent-Type: application/csvcontent_disposition: attachment; filename=Export.csvContent-Length: 41547|', AND MORE code....` so it's printing right, but not exporting as a file when the `button` is hit. – thesayhey Feb 29 '16 at 20:56
  • I can hae a look tomorrow to see how I fixed this before, but in the meantime, have a look here: http://docs.pylonsproject.org/projects/pyramid-cookbook/en/latest/templates/customrenderers.html – Thijs D Feb 29 '16 at 21:03
  • Figured it out! The issue with exporting was that I needed a `Renderer` and `View_Config` shown at the bottom of this link: http://docs.pylonsproject.org/projects/pyramid-cookbook/en/latest/templates/customrenderers.html. I added this: `@view_config(route_name='data', renderer='csv')` to the top of the function `export_results` along with a new `route`. Thanks Thijs! – thesayhey Mar 01 '16 at 16:07
  • I also changed the response per your suggestion and it worked for the filename naming convention. The only thing added is what I mentioned with the `view_config` addition. – thesayhey Mar 01 '16 at 17:05