1
votes

I'm getting "TypeError: cannot unpack non-iterable User object" when doing a post command to my flask app. I managed to manually add user to the DB. When I'm trying to create another user using the post endpoint, I'm getting the correct validation error that the email exists. But when I'm trying to post a new one, I'm getting the error: TypeError: cannot unpack non-iterable User object

I'm using Python 3.7.4 Flask 1.1.1 flask-marshmallow 0.10.1

This is my model:

class User(db.Model, UserMixin):
__tablename__ = "user"
__table_args__ = {'extend_existing': True} 


id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(120), index=True, unique=True, nullable=False)
password = db.Column(db.String(128), nullable=False)
stride_account_id = db.Column(db.Integer, db.ForeignKey('stride_account.id'),
                           nullable=True)



def __repr__(self):
    return '<User {} with password {}>'.format(self.email, self.password)

def set_password(self, password):
    self.password = bcrypt.generate_password_hash(password)

def check_password(self, password):
    return bcrypt.check_password_hash(self.password, password)


def generate_auth_token(self):
    """ Create a jwt token for the user to access the api """
    session_exp = datetime.utcnow() + timedelta(minutes=15)
    if current_app.config['APP_CONFIG'] != 'config.Production':
        session_exp = datetime.utcnow() + timedelta(hours=12)
    payload = {
        'sub': self.id,
        'iat': datetime.utcnow(),
        'exp': session_exp
    }
    token = jwt.encode(payload, current_app.config['SECRET_KEY'])
    return token.decode('unicode_escape')

def save(self):
    db.session.add(self)
    db.session.commit()

This is the schema:

class UserSchema(ma.ModelSchema):

email = field_for(User, 'email', required=True, 
    validate=[
    must_not_be_blank,
    validate.Email(),
    validators.validate_email]
)

password = field_for(User, 'password', required=True,
    validate=[
    must_not_be_blank,
    validators.validate_password]   
)

class Meta:
    model = User
    load_only = ('password',)

My view

lass UserView(Resource):

def get(self):
    user = User.query.filter(id='1')
    return 'Hello World'

@data_required
def post(self):
    data = request.get_json()#json.loads(request.data)
    print('data is: ', data)

    user, errors =  serializers.UserSchema().load(data)
    print('Hoooraaay')
    # user = User(email=data['email'], password=data['password'])
    user.set_password(user.password)
    user.save()  

    return serializers.UserSchema().jsonify(user)  

The full error message is:

[2019-09-28 17:36:35,465] ERROR in app: Exception on /api/user [POST]
Traceback (most recent call last):
  File "/Users/ronshteinberg/env/stride/lib/python3.7/site-packages/flask/app.py", line 1949, in full_dispatch_request
    rv = self.dispatch_request()
  File "/Users/ronshteinberg/env/stride/lib/python3.7/site-packages/flask/app.py", line 1935, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/Users/ronshteinberg/env/stride/lib/python3.7/site-packages/flask_restful/__init__.py", line 458, in wrapper
    resp = resource(*args, **kwargs)
  File "/Users/ronshteinberg/env/stride/lib/python3.7/site-packages/flask/views.py", line 89, in view
    return self.dispatch_request(*args, **kwargs)
  File "/Users/ronshteinberg/env/stride/lib/python3.7/site-packages/flask_restful/__init__.py", line 573, in dispatch_request
    resp = meth(*args, **kwargs)
  File "/Users/ronshteinberg/development/stride-core/app/decorators.py", line 13, in wrapped_view
    return view(*args, **kwargs)
  File "/Users/ronshteinberg/development/stride-core/app/accounts/views.py", line 20, in post
    user, errors =  serializers.UserSchema().load(data)
  File "/Users/ronshteinberg/env/stride/lib/python3.7/site-packages/marshmallow_sqlalchemy/schema.py", line 214, in load
    return super().load(data, **kwargs)
  File "/Users/ronshteinberg/env/stride/lib/python3.7/site-packages/marshmallow/schema.py", line 720, in load
    data, many=many, partial=partial, unknown=unknown, postprocess=True
  File "/Users/ronshteinberg/env/stride/lib/python3.7/site-packages/marshmallow/schema.py", line 898, in _do_load
    raise exc
marshmallow.exceptions.ValidationError: {'email': ['Email already exist']}
127.0.0.1 - - [28/Sep/2019 17:36:35] "POST /api/user HTTP/1.1" 500 -
data is:  {'email': '[email protected]', 'password': 'Qwert12345'}
[2019-09-28 17:36:40,644] ERROR in app: Exception on /api/user [POST]
Traceback (most recent call last):
  File "/Users/ronshteinberg/env/stride/lib/python3.7/site-packages/flask/app.py", line 1949, in full_dispatch_request
    rv = self.dispatch_request()
  File "/Users/ronshteinberg/env/stride/lib/python3.7/site-packages/flask/app.py", line 1935, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/Users/ronshteinberg/env/stride/lib/python3.7/site-packages/flask_restful/__init__.py", line 458, in wrapper
    resp = resource(*args, **kwargs)
  File "/Users/ronshteinberg/env/stride/lib/python3.7/site-packages/flask/views.py", line 89, in view
    return self.dispatch_request(*args, **kwargs)
  File "/Users/ronshteinberg/env/stride/lib/python3.7/site-packages/flask_restful/__init__.py", line 573, in dispatch_request
    resp = meth(*args, **kwargs)
  File "/Users/ronshteinberg/development/stride-core/app/decorators.py", line 13, in wrapped_view
    return view(*args, **kwargs)
  File "/Users/ronshteinberg/development/stride-core/app/accounts/views.py", line 20, in post
    user, errors =  serializers.UserSchema().load(data)
TypeError: cannot unpack non-iterable User object

Thanks in advance

2
Please post the complete error message.andole
Posted the full error, thanksRon Shteinberg
What is the User object? Did you expect it to be iterable? Did you expect serializers.UserSchema().load(data) to return something that was iterable?wwii
The object in the post. It is not supposed to be iterable. You can see in the View that I'm expecting a user object. I have no idea what and where is the code trying to iterateRon Shteinberg

2 Answers

1
votes

SO related above and the same issue:

in previous versions of

flask-sqlachemy OR flask-marshmallow

load function were returned 2 values

user, errors =  serializers.UserSchema().load(data)

after some updates in this source packages it started return one value, so to fix it you need to assign 1 value for response:

user =  serializers.UserSchema().load(data)

correct way to handle validation errors:

        try:
            obj = schema.load(data)
        except ValidationError as error:
            print(error.messages)
0
votes

I found the issue. The code was copied from someplace and it seems that serializers.UserSchema().load(data) doesn't return a tuple,just the object So the line should be:

user =  serializers.UserSchema().load(data)