Skip to content

Instantly share code, notes, and snippets.

@xaiki
Last active June 29, 2019 06:22
Show Gist options
  • Save xaiki/a993231192b18836c0dfcd1233ef7331 to your computer and use it in GitHub Desktop.
Save xaiki/a993231192b18836c0dfcd1233ef7331 to your computer and use it in GitHub Desktop.
SAFRS can't split out models definition

README

Trying to use SAFRS i've structured my App to have separated models, but when i do so I somehow get session ownership issues like the ones described here: https://stackoverflow.com/questions/24291933/sqlalchemy-object-already-attached-to-session

└[cochabamba] python3 server.py                                                      15:12:19
/home/xaiki/src/Urissane/cerberus/python/virtualenv/lib/python3.7/site-packages/safrs/swagger_doc.py:34: YAMLLoadWarning: calling yaml.load() without Loader=... is deprecated, as the default Loader is unsafe. Please read https://msg.pyyaml.org/load for full details.
yaml_doc = yaml.load(raw_doc)
Starting API: http://0.0.0.0:5000/api
Traceback (most recent call last):
File "server.py", line 17, in <module>
  db.session.add(user)
File "/home/xaiki/src/Urissane/cerberus/python/virtualenv/lib/python3.7/site-packages/sqlalchemy/orm/scoping.py", line 162, in do
  return getattr(self.registry(), name)(*args, **kwargs)
File "/home/xaiki/src/Urissane/cerberus/python/virtualenv/lib/python3.7/site-packages/sqlalchemy/orm/session.py", line 1948, in add
  self._save_or_update_state(state)
File "/home/xaiki/src/Urissane/cerberus/python/virtualenv/lib/python3.7/site-packages/sqlalchemy/orm/session.py", line 1961, in _save_or_update_state
  self._save_or_update_impl(state)
File "/home/xaiki/src/Urissane/cerberus/python/virtualenv/lib/python3.7/site-packages/sqlalchemy/orm/session.py", line 2311, in _save_or_update_impl
  self._update_impl(state)
File "/home/xaiki/src/Urissane/cerberus/python/virtualenv/lib/python3.7/site-packages/sqlalchemy/orm/session.py", line 2294, in _update_impl
  to_attach = self._before_attach(state, obj)
File "/home/xaiki/src/Urissane/cerberus/python/virtualenv/lib/python3.7/site-packages/sqlalchemy/orm/session.py", line 2382, in _before_attach
  % (state_str(state), state.session_id, self.hash_key)
sqlalchemy.exc.InvalidRequestError: Object '<User at 0x7f0fa61f3c50>' is already attached to session '1' (this is '2')
import os
import sys
from flask import Flask
from safrs import SAFRSAPI
from flask import redirect
from database import db
# APP Initialization
#
app = Flask('cerberus server')
app.config.update( SQLALCHEMY_DATABASE_URI = 'sqlite:///test.db',
SQLALCHEMY_TRACK_MODIFICATIONS = False,
DEBUG = True)
import user
class Models():
'''Python why you do this to me ?'''
def __init__(self):
self.User = user.User
models = Models()
db.init_app(app)
ROOT_PATH = os.path.dirname(os.path.realpath(__file__))
os.environ.update({'ROOT_PATH': ROOT_PATH})
HOST = sys.argv[1] if len(sys.argv) > 1 else '0.0.0.0'
PORT = 5000
API_PREFIX = '/api/v1'
api = SAFRSAPI(app, port=PORT, host=HOST, prefix=API_PREFIX)
print('Starting API: http://{}:{}/api'.format(HOST,PORT))
@app.route('/')
def goto_api():
return redirect(API_PREFIX)
@app.teardown_appcontext
def shutdown_session(exception=None):
'''cfr. http://flask.pocoo.org/docs/0.12/patterns/sqlalchemy/'''
db.session.remove()
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
Flask
safrs
sqlalchemy
#!/usr/bin/env python
#
import sys
import os
from app import app, db, models, HOST, PORT
ROOT_PATH = os.path.dirname(os.path.realpath(__file__))
os.environ.update({'ROOT_PATH': ROOT_PATH})
sys.path.append(ROOT_PATH)
# Start the application
with app.app_context():
db.create_all()
user = models.User(username='test')
db.session.add(user)
db.session.commit()
for m in models.User.query.all():
db.session.delete(m)
db.commit()
app.run(host=HOST, port = PORT)
# this goes to /models/user.py
# /models/__init__.py will be something like:
# import os
# import glob
# __all__ = [os.path.basename(f)[:-3]
# for f in glob.glob(os.path.dirname(__file__) + "/*.py")]
from database import db
from safrs import SAFRSBase
from sqlalchemy import Column, Integer, String
SAFRSBase.db_commit = False
class User(SAFRSBase, db.Model):
'''
description: User description
'''
__tablename__ = 'Users'
id = db.Column(String, primary_key=True)
username = db.Column(db.String(32), index=True)
@xaiki
Copy link
Author

xaiki commented Jun 28, 2019

thanks for pointing that out, with
SAFRSBase.db_commit = False this particular workflow passes, but now i run into the same issues with a model coming from a query.all()

i've updated the gist to show the behaviour:

└[cochabamba] python3 server.py                                                      19:48:48
/home/xaiki/src/Urissane/cerberus/python/virtualenv/lib/python3.7/site-packages/safrs/swagger_doc.py:34: YAMLLoadWarning: calling yaml.load() without Loader=... is deprecated, as the default Loader is unsafe. Please read https://msg.pyyaml.org/load for full details.
  yaml_doc = yaml.load(raw_doc)
Starting API: http://0.0.0.0:5000/api
Traceback (most recent call last):
  File "server.py", line 21, in <module>
    db.session.delete(m)
  File "/home/xaiki/src/Urissane/cerberus/python/virtualenv/lib/python3.7/site-packages/sqlalchemy/orm/scoping.py", line 162, in do
    return getattr(self.registry(), name)(*args, **kwargs)
  File "/home/xaiki/src/Urissane/cerberus/python/virtualenv/lib/python3.7/site-packages/sqlalchemy/orm/session.py", line 1983, in delete
    self._delete_impl(state, instance, head=True)
  File "/home/xaiki/src/Urissane/cerberus/python/virtualenv/lib/python3.7/site-packages/sqlalchemy/orm/session.py", line 1995, in _delete_impl
    to_attach = self._before_attach(state, obj)
  File "/home/xaiki/src/Urissane/cerberus/python/virtualenv/lib/python3.7/site-packages/sqlalchemy/orm/session.py", line 2382, in _before_attach
    % (state_str(state), state.session_id, self.hash_key)
sqlalchemy.exc.InvalidRequestError: Object '<User at 0x7f9cb3b97450>' is already attached to session '1' (this is '2')

@thomaxxl
Copy link

can you try to use db.session.query(User) instead?

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