pythonpython-3.xflaskflask-mailturi-create

Flask AssertionError While Trying to "POST"


I am brand new to python as of about 3 days ago and I need to build a prototype python server for an iOS work project. I followed a tutorial for the initial build.

When I perform a "POST" request, I get an error. Here is my full code, followed by the error I'm receiving in the Terminal when a "POST" request is submitted.

PS. also fairly new to stack overflow so I'm sorry if I'm asking this question incorrectly

    import flask
from flask import Flask, request, jsonify
from flask_uploads import UploadSet, IMAGES, configure_uploads
from flask import make_response
from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Marshmallow
import turicreate as tc
import sys
from queue import Queue
import os
import uuid
import logging
from flask import send_from_directory
import threading
from marshmallow import fields
from marshmallow import post_load

app = Flask(__name__)
if __name__ == "__main__":
    # Only for debugging while developing
    app.run(host='0.0.0.0', debug=True)

#configure logging
logging.basicConfig( level=logging.DEBUG,
                     format='[%(levelname)s] - %(threadName)-10s : %(message)s')

#configure images destination folder
app.config['UPLOADED_IMAGES_DEST'] = './images'
images = UploadSet('images', IMAGES)
configure_uploads(app, images)

#configure sqlite database
basedir = os.path.abspath(os.path.dirname(__file__))
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'facerecognition.sqlite')
db = SQLAlchemy(app)
ma = Marshmallow(app)

#model/users is a many to many relationship,  that means there's a third #table containing user id and model id
users_models = db.Table('users_models',
                        db.Column("user_id", db.Integer, db.ForeignKey('user.id')),
                        db.Column("model_id", db.Integer, db.ForeignKey('model.version'))
                        )
# model table
class Model(db.Model):
    version = db.Column(db.Integer, primary_key=True)
    url = db.Column(db.String(100))
    users = db.relationship('User', secondary=users_models)

# user table
class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(300))
    position = db.Column(db.String(300))

    def __init__(self, name, position):
        self.name = name
        self.position = position

#user schema
class UserSchema(ma.Schema):
    class Meta:
        fields = ('id', 'name', 'position')
#model schema
class ModelSchema(ma.Schema):
    version = fields.Int()
    url = fields.Method("add_host_to_url")
    users = ma.Nested(UserSchema, many=True)
    # this is necessary because we need to append the current host to the model url
    def add_host_to_url(self, obj):
        return request.host_url + obj.url

#initialize everything
user_schema = UserSchema()
users_schema = UserSchema(many=True)
model_schema = ModelSchema()
models_schema = ModelSchema(many=True)
db.create_all()

#error handlers
@app.errorhandler(404)
def not_found(error):
    return make_response(jsonify({'error': 'not found'}), 404)

@app.errorhandler(400)
def not_found(error):
    return make_response(jsonify({'error': 'bad request'}), 400)

#register user
@app.route("/testImages/face-recognition/api/v1.0/user/register", methods=['POST'])
def register_user():
    if not request.form or not 'name' in request.form:
        return make_response(jsonify({'status': 'failed', 'error': 'bad request', 'message:' : 'Name is required'}), 400)
    else:
        name = request.form['name']
        position = request.form.get('position')
        if position is None:
            position = ""
        newuser = User(name, position)
        db.session.add(newuser)
        db.session.commit()
        if 'photos' in request.files:
            uploaded_images = request.files.getlist('photos')
            save_images_to_folder(uploaded_images, newuser)
        return jsonify({'status' : 'success', 'user' :  user_schema.dump(newuser).data })

#function to save images to image directory
def save_images_to_folder(images_to_save, user):
    for a_file in images_to_save:
        # save images to images folder using user id as a subfolder name
        images.save(a_file, str(user.id), str(uuid.uuid4()) + '.')

    # get the last trained model
    model = Model.query.order_by(Model.version.desc()).first()
    if model is not None:
        # increment the version
        queue.put(model.version + 1)
    else:
        # create first version
        queue.put(1)

    @app.route("/testImages/face-recognition/api/v1.0/model/info" , methods=['GET'])
    def get_model_info():
        models_schema.context['request'] = request
        model = Model.query.order_by(Model.version.desc()).first()
        if model is None:
            return make_response(jsonify({'status': 'failed', 'error': 'model is not ready'}), 400)
        else:
            return jsonify({'status' : 'success', 'model' : model_schema.dump(model).data})

#serve models
@app.route('/models/')
def download(filename):
    return send_from_directory('models', filename, as_attachment=True)



def train_model():
    while True:
        #get the next version
        version = queue.get()
        logging.debug('loading images')
        data = tc.image_analysis.load_images('images', with_path=True)

        # From the path-name, create a label column
        data['label'] = data['path'].apply(lambda path: path.split('/')[-2])

        # use the model version to construct a filename
        filename = 'Faces_v' + str(version)
        mlmodel_filename = filename + '.mlmodel'
        models_folder = 'models/'

        # Save the data for future use
        data.save(models_folder + filename + '.sframe')

        result_data = tc.SFrame( models_folder + filename +'.sframe')
        train_data = result_data.random_split(0.8)

        #the next line starts the training process
        model = tc.image_classifier.create(train_data, target='label', model='resnet-50', verbose=True)

        db.session.commit()
        logging.debug('saving model')
        model.save( models_folder + filename + '.model')
        logging.debug('saving coremlmodel')
        model.export_coreml(models_folder + mlmodel_filename)

        # save model data in database
        modelData = Model()
        modelData.url = models_folder + mlmodel_filename
        classes = model.classes
        for userId in classes:
            user = User.query.get(userId)
            if user is not None:
                modelData.users.append(user)
        db.session.add(modelData)
        db.session.commit()
        logging.debug('done creating model')
        # mark this task as done
        queue.task_done()

#configure queue for training models
queue = Queue(maxsize=0)
thread = threading.Thread(target=train_model, name='TrainingDaemon')
thread.setDaemon(False)
thread.start()```

Here is the Error I get In the Terminal

[DEBUG] - TrainingDaemon : loading images
127.0.0.1 - - [03/Jan/2020 11:52:39] "POST /testImages/face-recognition/api/v1.0/user/register HTTP/1.1" 500 -
[INFO] - Thread-3   : 127.0.0.1 - - [03/Jan/2020 11:52:39] "POST /testImages/face-recognition/api/v1.0/user/register HTTP/1.1" 500 -
Traceback (most recent call last):
  File "/Users/me/venv/lib/python3.7/site-packages/flask/app.py", line 2463, in __call__
    return self.wsgi_app(environ, start_response)
  File "/Users/me/venv/lib/python3.7/site-packages/flask/app.py", line 2449, in wsgi_app
    response = self.handle_exception(e)
  File "/Users/me/venv/lib/python3.7/site-packages/flask/app.py", line 1866, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/Users/me/venv/lib/python3.7/site-packages/flask/_compat.py", line 39, in reraise
    raise value
  File "/Users/me/venv/lib/python3.7/site-packages/flask/app.py", line 2446, in wsgi_app
    response = self.full_dispatch_request()
  File "/Users/me/venv/lib/python3.7/site-packages/flask/app.py", line 1951, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/Users/me/venv/lib/python3.7/site-packages/flask/app.py", line 1820, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/Users/me/venv/lib/python3.7/site-packages/flask/_compat.py", line 39, in reraise
    raise value
  File "/Users/me/venv/lib/python3.7/site-packages/flask/app.py", line 1949, in full_dispatch_request
    rv = self.dispatch_request()
  File "/Users/me/venv/lib/python3.7/site-packages/flask/app.py", line 1935, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/Users/me/Desktop/GorillaFace/app.py", line 103, in register_user
    save_images_to_folder(uploaded_images, newuser)
  File "/Users/me/Desktop/GorillaFace/app.py", line 121, in save_images_to_folder
    @app.route("/testImages/face-recognition/api/v1.0/model/info" , methods=['GET'])
  File "/Users/me/venv/lib/python3.7/site-packages/flask/app.py", line 1314, in decorator
    self.add_url_rule(rule, endpoint, f, **options)
  File "/Users/me/venv/lib/python3.7/site-packages/flask/app.py", line 90, in wrapper_func
    "A setup function was called after the "
AssertionError: A setup function was called after the first request was handled.  This usually indicates a bug in the application where a module was not imported and decorators or other functionality was called too late.
To fix this make sure to import all your view modules, database models and everything related at a central place before the application starts serving requests.
Exception in thread TrainingDaemon:
Traceback (most recent call last):
  File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.7/lib/python3.7/threading.py", line 917, in _bootstrap_inner
    self.run()
  File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.7/lib/python3.7/threading.py", line 865, in run
    self._target(*self._args, **self._kwargs)
  File "/Users/me/Desktop/GorillaFace/app.py", line 159, in train_model
    model = tc.image_classifier.create(train_data, target='label', model='resnet-50', verbose=True)
  File "/Users/me/venv/lib/python3.7/site-packages/turicreate/toolkits/image_classifier/image_classifier.py", line 225, in create
    raise TypeError('"dataset" must be of type SFrame.')
TypeError: "dataset" must be of type SFrame.

What I've tried:

Like I said I'm still new to python so I don't know much about troubleshooting python code. The assertion error seems to be saying something was not imported correctly, so I re-installed, flask-uploads,Flask-SQLAlchemy,flask-marshmallow, marshmallow-sqlalchemy. I also made sure all the imports looked like it did in the tutorial.

Anyone have any ideas as to what I need to do to not get this error? what this code should do is allow me to post a name, position, and photos to the server which will then train a ML model to recognize the new photos.


Solution

  • Error shows in which line it has problem

    model = tc.image_classifier.create(...)
    

    and it has problem with

    "dataset" must be of type SFrame. 
    

    so use at least print() and print(type(..)) to check variablse which you use in this line and see if you use SFrame.