valq7711 / ombott

This is bottle spin-off (One More BOTTle)
MIT License
8 stars 5 forks source link

Ombott 2.0.0 incompatible with Python 3.10.12 io.TextIOWrapper. #16

Open davidmanns opened 1 month ago

davidmanns commented 1 month ago

I have a py4web controller that loads an empty database from a csv file taken from my production file using db.import_from_csv_file. I get the following error.

'BytesIOProxy' object has no attribute 'readable'

BytesIOProxy is defined by Ombott. io.TextIOWrapper expects it to supply 'readable' and 'seekable' attributes, apparently. The code worked with Ombott 1.0.0.

Here is the code of the py4web controller:

@action("db_restore", method=['POST', 'GET']) @preferred @checkaccess('admin') def db_restore(): access = session['access'] #for layout.html header = f"Restore {SOCIETY_SHORT_NAME} database from backup file"

form = Form([Field('overwrite_existing_database', 'boolean',
                    default=False, comment='clear if new empty database'),
            Field('backup_file', 'upload', uploadfield = False)],
            submit_value = 'Restore')

if form.accepted:
    try:
        with io.TextIOWrapper(form.vars.get('backup_file').file, encoding='utf-8') as backup_file:
            if form.vars.get('overwrite_existing_database'):
                for tablename in db.tables: #clear out existing database
                    db(db[tablename]).delete()
            db.import_from_csv_file(backup_file, id_map={} if form.vars.get('overwrite_existing_database') else None)   #, restore=True won't work in MySQL)
            flash.set(f"{SOCIETY_SHORT_NAME} Database Restored from {form.vars.get('backup_file').raw_filename}")
            session['logged_in'] = False
            redirect('index')
    except Exception as e:
        flash.set(f"{str(e)}")

return locals( )
valq7711 commented 1 month ago

test please pip install ombott==2.1

davidmanns commented 1 month ago

Now I get the error:

I/O operation on closed file.

valq7711 commented 1 month ago

Now I get the error:

I/O operation on closed file.

this means that the request body is already closed, but someone is trying to read it, possible problem is return locals(), which includes backup_file.

davidmanns commented 1 month ago

No, the file processing is all within the controller. The exception occurs within the TextIOWrapper call.

I wrote a minimal py4web app to demonstrate the problem, here is the init,py file:

import io from py4web import action, request, response, redirect, URL, Field from py4web.utils.form import Form

@action("index") def index(): redirect(URL('upload'))

@action('upload', method=['GET', 'POST']) @action.uses('form.html') def upload(): form = Form([Field('file', 'upload')]) content = "no file read yet" if form.accepted:

Get the uploaded file

    uploaded_file = form.vars['file']

    # Open the uploaded file using TextIOWrapper
    with io.TextIOWrapper(uploaded_file.file, encoding='utf-8') as text_file:
        content = text_file.read()

return dict(form=form, content=content)

and here is form.html:

[[=form]] [[=content]]

However, I have got no further with debugging than determining that the TextIOWrapper call itself fails.

valq7711 commented 1 month ago

should work now pip install ombott==2.2

davidmanns commented 1 month ago

great, looking good!