How to use Factory Boy with SQLAlchemy session (Lazy Loaded) correctly?
Asked Answered
M

2

5

I just run into a problem with my testsuite. I am using a setup with nosetests, SQLAlchemy, Flask and Factory-Boy

I have the following code:

def _create_fixtures(self):
    self.user = UserFactory()
    pprint(db.query(User).all())
    db.add(self.user)
    pprint(db.query(User).all())

witch returns following:

[<User #1>, <User #2>]
[<User #1>, <User #2>]

My UserFactory looks like this:

class UserFactory(Factory):
    FACTORY_FOR = User
    FACTORY_SESSION = db
    email = Sequence(lambda n: 'user{0}@wohnortfinder.com'.format(n))
    password = "password"
    username = Sequence(lambda n: 'user{0}'.format(n))

(yes I am using the normal Factory and not he SQLAlchemy factory, cause this didn't work either)

Why isn't my Factory Object stored to db? It doesn't raise an error, it just doesn't save. I mean even when the current transaction is not committed yet, the query later should queries the actual transaction, shouldn't it?

Oddly when I manually commit the session, it raises an error.

InvalidRequestError: No transaction is begun.

Even though I began a transaction when creating the session object.

def init_engine(uri, **kwargs):
    global engine
    engine = create_engine(uri, **kwargs)
    Base.metadata.create_all(engine)
    db.begin()
    return engine


engine = None

db = scoped_session(lambda: create_session(bind=engine))

any idea why this is not working?

Thanks for your thoughts

Mainsail answered 5/4, 2014 at 22:52 Comment(0)
W
13

You can define the factory_boy factories without setting the SQLAlchemy session and then set it up in between initialising the Flask app and using the factories by assigning to the _meta property of the factory class:

db_session = set_up_a_db_session_somehow()
MyFactoryClass._meta.sqlalchemy_session = db_session

This seems to work fine with a scoped session.

William answered 21/9, 2014 at 3:23 Comment(0)
M
1

Ok I see now one of my mistakes. I create a scoped session. Instead I should be using a normal session for my application. The problem here is - how can I lazy init a normal session?

I will thread this issue in another question

for the scoped session I found the answer to this particular issue. The thing is, with the scoped session my whole app won't work but the tests will..

this code works with the scoped session, for this issue.

def _create_fixtures(self):
    db.begin()
    self.user = UserFactory()
    db.add(self.user)
    db.commit()
Mainsail answered 6/4, 2014 at 4:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.