Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SQLAlchemy Error about implicitly combining uid columns #1

Open
dcrosta opened this issue Jun 1, 2018 · 2 comments
Open

SQLAlchemy Error about implicitly combining uid columns #1

dcrosta opened this issue Jun 1, 2018 · 2 comments

Comments

@dcrosta
Copy link

dcrosta commented Jun 1, 2018

I'm trying to set up PSA with Flask & SQLAlchemy. I've gotten as far as calling init_social, but as soon as I try to access my app (run flask shell or load a page in flask run, etc), I get this error:

Traceback (most recent call last):
[...]
  File "/Users/dcrosta/src/myproject/myproject/core.py", line 91, in set_up_auth
    init_social(app, db.session)
  File "/Users/dcrosta/.virtualenvs/myproject/lib/python3.6/site-packages/social_flask_sqlalchemy/models.py", line 80, in init_social
    UserSocialAuth.uid = Column(String(UID_LENGTH))
  File "/Users/dcrosta/.virtualenvs/myproject/lib/python3.6/site-packages/sqlalchemy/ext/declarative/api.py", line 69, in __setattr__
    _add_attribute(cls, key, value)
  File "/Users/dcrosta/.virtualenvs/myproject/lib/python3.6/site-packages/sqlalchemy/ext/declarative/base.py", line 658, in _add_attribute
    cls.__mapper__.add_property(key, value)
  File "/Users/dcrosta/.virtualenvs/myproject/lib/python3.6/site-packages/sqlalchemy/orm/mapper.py", line 1854, in add_property
    self._configure_property(key, prop, init=self.configured)
  File "/Users/dcrosta/.virtualenvs/myproject/lib/python3.6/site-packages/sqlalchemy/orm/mapper.py", line 1638, in _configure_property
    prop = self._property_from_column(key, prop)
  File "/Users/dcrosta/.virtualenvs/myproject/lib/python3.6/site-packages/sqlalchemy/orm/mapper.py", line 1768, in _property_from_column
    raise sa_exc.InvalidRequestError(msg)
sqlalchemy.exc.InvalidRequestError: Implicitly combining column social_auth_usersocialauth.uid with column social_auth_usersocialauth.uid under attribute 'uid'.  Please configure one or more attributes for these same-named columns explicitly.

I'm using:

$ pip list | egrep -i "social|flask|sqlalchemy"
Flask                            1.0.2
Flask-Login                      0.4.1
Flask-SQLAlchemy                 2.3.2
python-social-auth               0.3.6
social-auth-app-flask            1.0.0
social-auth-app-flask-sqlalchemy 1.0.1
social-auth-core                 1.7.0
social-auth-storage-sqlalchemy   1.1.0
SQLAlchemy                       1.2.8

As near as I can tell, there's only one actual definition of uid, which is at https://github.com/python-social-auth/social-app-flask-sqlalchemy/blob/master/social_flask_sqlalchemy/models.py#L80 -- everywhere else in the class hierarchy, uid is assigned to None. But I'm hoping that there's something obvious I've missed here, or something you've run into before that can help.

Thanks!

@dcrosta
Copy link
Author

dcrosta commented Jun 2, 2018

Ah, I've found the issue. When running with flask run ..., it looks like Flask loads the app module several times. In my particular case, I use a factory function to create the application object, which ultimately results in init_social being called several times. Here's a small reproducing case:

social.py

from flask import Flask
from models import db
from social_flask_sqlalchemy.models import init_social


def create_application():
    app = Flask(__name__)

    app.config["SOCIAL_AUTH_USER_MODEL"] = "models.User"
    app.config["SOCIAL_AUTH_STORAGE"] = "social_flask_sqlalchemy.models.FlaskStorage"
    init_social(app, db.session)

    return app


application = create_application()

models.py

from flask_sqlalchemy import SQLAlchemy


db = SQLAlchemy()


class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(256))
    name = db.Column(db.String(256))
    email = db.Column(db.String(256))

Run with FLASK_APP=social flask run to see the traceback.

I have, for now, worked around this by returning a singleton from my app factory, but this is a bit janky. If there was some way this could be fixed in social-auth itself, that would be easier for me or anyone else who uses factories like I do (which makes testing a lot nicer).

@miiichael
Copy link

Specifically, this footgun is the result of init_social() always importing the module your USER_MODEL is in, even if (as I've just discovered) your app is trivial enough that you put your model(s) in the same module as the app itself...

In @dcrosta's example, I think all that was needed was an if __name__ == "__main__": before the last line of social.py.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

2 participants