smari / voting

A simulator for voting systems.
27 stars 10 forks source link

Uploading vote table from xlsx file - AttributeError: 'SpooledTemporaryFile' object has no attribute 'seekable' #95

Open PeturOA opened 3 years ago

PeturOA commented 3 years ago

I was running some simulations recently, and discovered that the file upload had broken. I do not remember when I last tried to upload a vote table xlsx file, so I do not know exactly when this became a problem, but at least it was most definitely not a problem when I was working on the file upload feature last year.

The issue is when uploading votes from an xlsx file, and loading the filestream into a workbook using openpyxl. The filestream is of type SpooledTemporaryFile, but openpyxl seems to expect it to implement BufferedIOBase or something like that (I'm no expert in these IO implementations)

Here's the relevant code:

@app.route('/api/votes/upload/', methods=['POST'])
def upload_votes():
    ...
    f = request.files['file']
    res = util.load_votes_from_stream(f.stream, f.filename)
    ...
def load_votes_from_stream(stream, filename):
    rd = []
    if filename.endswith(".csv"):
        ...
    elif filename.endswith(".xlsx"):
        book = openpyxl.load_workbook(stream)
        ...
    else:
        return None, None, None

I found this related werkzeug issue from two years ago. https://github.com/pallets/werkzeug/issues/1344

It seems to have been resolved, so I tried just updating werkzeug and flask, as well as openpyxl. But that did not solve this, so I added a couple of lines to fix this, although I'm not satisfied with that solution:

if not hasattr(stream, "seekable") and hasattr(stream, "_file"):
    stream.seekable = stream._file.seekable

See PR: https://github.com/smari/voting/pull/94

smari commented 3 years ago

Merged the temporary fix but leaving this issue open, as the XLSX import apparently needs a more permanent fix.