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

Why is session part of the declarative API? #11

Closed
dtheodor opened this issue Jun 28, 2015 · 6 comments

Comments

@dtheodor
Copy link

commented Jun 28, 2015

Hi,

My SQL Alchemy models are totally decoupled from ways to access them (so from both an engine and a session). My session objects are created depending on the python process that makes use of the models (for instance, I am using a scoped_session for my web app, a plain Session object for one-off scripts).

This makes it impossible to use this library. Why is it a requirement to pass the session to the model declaration?

@jmcarp

This comment has been minimized.

Copy link
Contributor

commented Jun 29, 2015

As of #8, sqla_session should only be used for deserializing related fields, which some applications might not need to do. We could allow users to omit the session in the schema declaration and raise an error on attempting to deserialize.

Alternatively, would it help if sqla_session could be a callable as well as a session? Then you could pass a function that would check some configuration variable and return the appropriate type of session. This might not fit what you're doing--just curious.

@hartror

This comment has been minimized.

Copy link

commented Jun 29, 2015

@jmcarp a callable would help but being able to pass it to the constructor would be best. When you're not using a thread local SQLA session (such as with gevent servers) you need to be able to pass the session.

@dtheodor if you need a stop gap just set sqla_session to object(), as long as you don't have marshmallow getting related fields then nothing will break.

@dtheodor

This comment has been minimized.

Copy link
Author

commented Jun 29, 2015

In the spirit of how a session is used in SQL Alchemy (which is that the session knows about the models, the models know not of the session), the right place (from the API perspective) for it to be passed would be in the dumps/loads methods:

author = author_schema.load(author_data, session=session)
session.add(author)
session.commit()

I really can't think of any other nice way for this (and is also the only way to support more "advanced" features like more than one session). My alternative is to put all the marshmallow schemas in a factory function that receives a session and declares the schemas with the correct session.

The callable solution would work but would require a lot of hackery (would have to create some global config object that points to the right session factory depending on some env. variable or something like that. So my models would not be coupled to a session but to a clunky config setup. I'd rather stay away from this and go with the schema factory method)

@sloria

This comment has been minimized.

Copy link
Member

commented Aug 28, 2015

I agree with @dtheodor's proposal to make session a parameter of ModelSchema.load. I'll implement this soon.

@sloria sloria closed this in 6d616e0 Aug 28, 2015

@sloria

This comment has been minimized.

Copy link
Member

commented Aug 28, 2015

It is now possible to pass session to the ModelSchema constructor or to load().

@aguegu

This comment has been minimized.

Copy link

commented Jun 16, 2016

My project uses Flask, SQLAlchemy + pyMysql and Marshmallow/marshmallow-sqlalchemy.

I implemented the declarative way to combine flask and SQLAlchemy.

There is a section

@app.teardown_appcontext
def shutdown_session(exception=None):
    db_session.remove()

To close the scoped session after every requset.

With sqla_session, I believe there will be two scoped sessions got involved in a request, one to the the .add()/.merge() job, and the other one within schema.

And the teardown_appcontext function only got the outside one removed.

But the inside one, the sqla_session, remains in the connection pool, but it got expired and closed by the server. So after idle for a while, I got OperationalError: (pymysql.err.OperationalError) (2013, 'Lost connection to MySQL server during query') from pymysql.

I believe this problem would be solved by removing the sqla_session from scheme meta, and pass in the outside session into the schema.load().

Thanks the issue got fixed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
5 participants
You can’t perform that action at this time.