Flask: How do I pass an uploaded file as input to a method? AttributeError: '_io.BytesIO' object has no attribute 'lower'

Issue

I’m completely new to flask (in fact I’ve just started this morning) and so far I’ve only managed to implement a basic upload function (taken from the flask doc). The file upload works but I just can’t seem to figure out how to pass the file into another method (mining). When I do, I always get the error message: AttributeError: ‘_io.BytesIO’ object has no attribute ‘lower’. It would mean the world to me to receive any kind of help! Thank you all in advance.

def mining(xes):
    log = xes_importer.apply(xes)
    tracefilter_log_pos = attributes_filter.apply_events(log, ["complete"], parameters={attributes_filter.Parameters.ATTRIBUTE_KEY: "lifecycle:transition", attributes_filter.Parameters.POSITIVE: True})
    variants = pm4py.get_variants_as_tuples(tracefilter_log_pos)
    Alpha(variants.keys())
    Heuristic(variants.keys(), 1, 0.5)


UPLOAD_FOLDER = '/Users/jenny/processmining_lab/uploads'
ALLOWED_EXTENSIONS = set(['xes'])

app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER


def allowed_file(filename):
    return '.' in filename and \
           filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

@app.route('/', methods=['GET', 'POST'])
def upload_file():
    if request.method == 'POST':
        # check if the post request has the file part
        if 'file' not in request.files:
            flash('No file part')
            return redirect(request.url)
        file = request.files['file']
        # If the user does not select a file, the browser submits an
        # empty file without a filename.
        if file.filename == '':
            flash('No selected file')
            return redirect(request.url)
        if file and allowed_file(file.filename):
            filename = secure_filename(file.filename)
            file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
            return mining(file)
    return '''
    <!doctype html>
    <title>Upload new File</title>
    <h1>Upload new File</h1>
    <form method=post enctype=multipart/form-data>
      <input type=file name=file>
      <input type=submit value=Upload>
    </form>
    '''

Here is the traceback

Solution

This depends on what you’re mining function looks like.

file is a werkzeug.FileStorage object which has it’s own various methods.

So (without seeing) your mining function it should probably be something like:

def mining(file_obj):

    lower_fname = file_obj.filename.lower()
    data = file_obj.read()

    # Do something

The AttributeError you mention sounds like you’re trying to run the lower method of something which doesn’t return a string.

As a side-note: it’s difficult to know where in your code this exception hasn’t occured as you never posted the full traceback.


EDIT

My mining function is actually at the top of the code I’ve inserted. I’ve also now included the traceback.

Looks like you’re using PM4Py for which this document states:

from pm4py.objects.log.importer.xes import importer as xes_importer
log = xes_importer.apply('<path_to_xes_file.xes>') 

So you need to actually pass a file path to the mining function.

I suggest changing your main code to do:

        if file and allowed_file(file.filename):
            sfilename = secure_filename(file.filename)
            output_path = os.path.join(app.config['UPLOAD_FOLDER'], sfilename)

            # Now save to this `output_path` and pass that same var to your mining function
            file.save(output_path)
            return mining(output_path)

Answered By – v25

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published