0

I'm slowly trying to build a small Rest API using Flask, Marshmallow, SQLAlchemy, and SQLite3. At some point in the recent future my simple "Get" call for the users table seemed to work, but later I started getting the same argument over and over when trying stuff out.

The error: "TypeError: string argument without an encoding"

This happens when trying localhost:5000/users in my browser. The exact line is 96 "users = Users.query.all()" and the exact function appears to be the SQLAlchemy.query() according to the stacktrace (I'll post below).

I've tried this simple method different ways via many a tutorial but no avail. Is it perhaps a Python 2 versus 3 thing? My small amount of code seems very much exactly how many tutorials are.

The code (the only module):

from flask import Flask
from flask_script import Manager, Server
from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Schema
from marshmallow import fields


app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///../campus.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = 'False'

db = SQLAlchemy(app)
manager = Manager(app)

manager.add_command("runserver", Server(
use_debugger=True,
use_reloader=True,
host='0.0.0.0'))


class Users(db.Model):
    user_id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(20), unique=True, nullable=False)
    is_admin = db.Column(db.Integer, nullable=False)
    password = db.Column(db.Integer, nullable=False)
    picture = db.Column(db.LargeBinary)

    def __repr__(self):
        return '<User %r>' % self.username


class Pins(db.Model):
    pin_id = db.Column(db.Integer, primary_key=True, unique=True, nullable=False)
    parent_id = db.Column(db.Integer, nullable=False)
    user_id = db.Column(db.Integer, nullable=False)
    master_comment = db.Column(db.Integer, nullable=False)
    x_coord = db.Column(db.Float, nullable=False)
    y_coord = db.Column(db.Float, nullable=False)
    picture = db.Column(db.LargeBinary)
    likes = db.Column(db.Integer, nullable=False)
    dislikes = db.Column(db.Integer, nullable=False)
    tags = db.Column(db.String(150))


class Comments(db.Model):
    comment_id = db.Column(db.Integer, primary_key=True, unique=True, nullable=False)
    parent_id = db.Column(db.Integer, nullable=False)
    user_id = db.Column(db.Integer, nullable=False)
    text = db.Column(db.String, nullable=False)
    likes = db.Column(db.Integer, nullable=False)
    dislikes = db.Column(db.Integer, nullable=False)


class UserSchema(Schema):
    user_id = fields.Int()
    username = fields.Str()
    is_admin = fields.Int()
    password = fields.Int()
    picture = fields.Raw()


class PinsSchema(Schema):
    pin_id = fields.Int()
    parent_id = fields.Int()
    user_id = fields.Int()
    master_comment = fields.Int()
    x_coord = fields.Float()
    y_coord = fields.Float()
    picture = fields.Raw()
    likes = fields.Int()
    dislikes = fields.Int()
    tags = fields.Str()


class CommentsSchema(Schema):
    comment_id = fields.Int()
    parent_id = fields.Int()
    user_id = fields.Int()
    text = fields.Str()
    likes = fields.Int()
    dislikes = fields.Int()


user_schema = UserSchema()
users_schema = UserSchema(many=True)

pin_schema = PinsSchema()
pins_schema = PinsSchema(many=True)

comment_schema = PinsSchema()
comments_schema = PinsSchema(many=True)


@app.route("/users")
def get_users():
    users = Users.query.all()
    return user_schema.jsonify(users)


if __name__ == '__main__':
    db.create_all()
    app.run()

My traceback:

    Traceback (most recent call last):
  File "/home/joshuasonn/PycharmProjects/SIUCampusMapServer/venv/lib/python3.6/site-packages/flask/app.py", line 1982, in wsgi_app
    response = self.full_dispatch_request()
  File "/home/joshuasonn/PycharmProjects/SIUCampusMapServer/venv/lib/python3.6/site-packages/flask/app.py", line 1614, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/home/joshuasonn/PycharmProjects/SIUCampusMapServer/venv/lib/python3.6/site-packages/flask/app.py", line 1517, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/home/joshuasonn/PycharmProjects/SIUCampusMapServer/venv/lib/python3.6/site-packages/flask/_compat.py", line 33, in reraise
    raise value
  File "/home/joshuasonn/PycharmProjects/SIUCampusMapServer/venv/lib/python3.6/site-packages/flask/app.py", line 1612, in full_dispatch_request
    rv = self.dispatch_request()
  File "/home/joshuasonn/PycharmProjects/SIUCampusMapServer/venv/lib/python3.6/site-packages/flask/app.py", line 1598, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "SIUCampusMapServer.py", line 96, in get_users
    users = Users.query.all()
  File "/home/joshuasonn/PycharmProjects/SIUCampusMapServer/venv/lib/python3.6/site-packages/sqlalchemy/orm/query.py", line 2737, in all
    return list(self)
  File "/home/joshuasonn/PycharmProjects/SIUCampusMapServer/venv/lib/python3.6/site-packages/sqlalchemy/orm/loading.py", line 98, in instances
    util.raise_from_cause(err)
  File "/home/joshuasonn/PycharmProjects/SIUCampusMapServer/venv/lib/python3.6/site-packages/sqlalchemy/util/compat.py", line 203, in raise_from_cause
    reraise(type(exception), exception, tb=exc_tb, cause=cause)
  File "/home/joshuasonn/PycharmProjects/SIUCampusMapServer/venv/lib/python3.6/site-packages/sqlalchemy/util/compat.py", line 187, in reraise
    raise value
  File "/home/joshuasonn/PycharmProjects/SIUCampusMapServer/venv/lib/python3.6/site-packages/sqlalchemy/orm/loading.py", line 79, in instances
    rows = [proc(row) for row in fetch]
  File "/home/joshuasonn/PycharmProjects/SIUCampusMapServer/venv/lib/python3.6/site-packages/sqlalchemy/orm/loading.py", line 79, in <listcomp>
    rows = [proc(row) for row in fetch]
  File "/home/joshuasonn/PycharmProjects/SIUCampusMapServer/venv/lib/python3.6/site-packages/sqlalchemy/orm/loading.py", line 493, in _instance
    loaded_instance, populate_existing, populators)
  File "/home/joshuasonn/PycharmProjects/SIUCampusMapServer/venv/lib/python3.6/site-packages/sqlalchemy/orm/loading.py", line 593, in _populate_full
    dict_[key] = getter(row)
  File "/home/joshuasonn/PycharmProjects/SIUCampusMapServer/venv/lib/python3.6/site-packages/sqlalchemy/engine/result.py", line 93, in __getitem__
    return processor(self._row[index])
  File "/home/joshuasonn/PycharmProjects/SIUCampusMapServer/venv/lib/python3.6/site-packages/sqlalchemy/sql/sqltypes.py", line 902, in process
    value = bytes(value)
TypeError: string argument without an encoding

Any help would be appreciated! I've tried rewriting a multitude of ways, and went through quite a lot of stackoverflow posts and github issues trying to figure this out.

0

1 Answer 1

1

Long story short, you have text data in some row in the picture column of the users table.

This is possible because unlike many other SQL implementations, SQLite has dynamic typing, compared to static. The type you give to a column defines its affinity, or in other words the recommended type for data stored in that column, but it is a recommendation, not a requirement. In the end you can have text data in an INTEGER column, or such as in your case, data using the TEXT storage class in a BLOB column.

An example:

In [2]: class User(Base):
   ...:     __tablename__ = 'user'
   ...:     id = Column(Integer, primary_key=True)
   ...:     picture = Column(LargeBinary)
   ...:     

In [3]: metadata.create_all()
...
2018-03-09 09:33:37,785 INFO sqlalchemy.engine.base.Engine 
CREATE TABLE user (
        id INTEGER NOT NULL, 
        picture BLOB, 
        PRIMARY KEY (id)
)
...

In [4]: engine.execute("insert into user (picture) values ('BANG!')")
Out[4]: <sqlalchemy.engine.result.ResultProxy at 0x7f7ad8bcc278>

Trying to fetch users does not end well:

In [5]: session.query(User).all()
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-5-f1275abaf1fd> in <module>()
----> 1 session.query(User).all()

...

~/Work/SO/lib/python3.6/site-packages/sqlalchemy/sql/sqltypes.py in process(value)
    900             def process(value):
    901                 if value is not None:
--> 902                     value = bytes(value)
    903                 return value
    904             return process

TypeError: string argument without an encoding

You'll have to go through your user data and fix manually. Using the typeof() function you can find the offending rows:

In [9]: session.query(User.id).\
   ...:     filter(func.typeof(User.picture) == 'text').\
   ...:     all()
Out[9]: [(1)]
Sign up to request clarification or add additional context in comments.

1 Comment

That was indeed the problem! I was far from figuring that out, thanks for your help and explanation!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.