question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Module scoped sessions

See original GitHub issue

Thanks for this awesome module!

I was wondering if it is possible to make a session, which would persist changes only inside its fixture scope. So if I make changes to the module scoped session, they’ll persist inside that module. Something that could be used like this:

# File test_book.py
@fixture(scope="module", autouse=True)
def book(module_db_session):
    book = Book(name="ABC")
    module_db_session.add(book)
    module_db_session.commit()
    return book

def test_book(db_session):
    # Don't use the fixture model, since it'll be bound to the `module_db_session`
    book = db_session.query(Book).get(1)
    book.name = "DEF"
    db_session.add(book)
    db_session.commit()

def test_book_doesnt_persist(book):
    assert book.name == "ABC"

# File test_other.py
@mark.xfail(reason="The book won't be available here!")
def test_other(db_session):
    db_session.query(Book).get(1)

The reasoning behind this is mostly speed, since it’s costly to create new instances every time you want to use them in a test.

Is something like this at all possible, or will I have to use setup_module and teardown_module, and manually make sure that no changes are persisted?

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:5 (2 by maintainers)

github_iconTop GitHub Comments

2reactions
layoastercommented, Apr 3, 2019

@jeancochrane I’m not using this library but rather my own fixtures with a very similar setup/implementation. In my case setting the scope to class behaves well so I’d say with a 98% certainty that your lib implementation should work fine too.

My fixtures implementation:

@pytest.fixture(scope="session")
def app():
    """Flask application for tests."""
    app = create_app(test=True)

    # setUp
    ctx = app.app_context()
    ctx.push()

    yield app

    # tearDown
    ctx.pop()

@pytest.fixture(scope="session")
def db(app):
    """Session-wide test database."""
    _db.app = app

    # Apply migrations (creating tables)
    Migrate(app, _db)
    upgrade(revision="head")

    yield _db

    # Undo migrations (removing tables)
    downgrade(revision="base")


@pytest.fixture(scope="function")
def db_session(db):
    """
    Database session as a fixture to isolate test from each other. Basically,
    test units get wrapped in database transactions that always get rolled back.
    """
    connection = db.engine.connect()
    transaction = connection.begin()

    options = dict(bind=connection, binds={})
    session = db.create_scoped_session(options=options)

    connection.force_close = connection.close
    transaction.force_rollback = transaction.rollback

    connection.close = lambda: None
    transaction.rollback = lambda: None
    session.close = lambda: None

    db.session = session

    yield session

    session.remove()
    transaction.force_rollback()
    connection.force_close()
1reaction
jeancochranecommented, Nov 29, 2018

This is an interesting question! If you were willing to modify the source, I think it’d be easy to extend current functionality to support differently-scoped sessions. We scope the fixtures with a decorator that could easily be swapped out to support a different scope:

https://github.com/jeancochrane/pytest-flask-sqlalchemy/blob/43e2c36e8f7083775a70fe73bc370a5dc4039fa5/pytest_flask_sqlalchemy/fixtures.py#L24-L25

As to whether this is a feature I’d be interested in bringing into the library, my instinct is to vote against it – the primary impetus for the creation of this library was that we had a bunch of module-scoped fixtures in our test suite and it became really hard to add or change tests because we had no reliable way of knowing what the state of the database was during any given test. Using this module did slow things down, but it was a tradeoff that we were willing to make, and the point of the module was to allow us to make it. That being said, I don’t have a great sense of how people are using this module outside of my own personal context, so if there’s a lot of desire for it I’d be happy to look at a PR.

Thanks for your kind words, I’m glad this work has been useful to you!

Read more comments on GitHub >

github_iconTop Results From Across the Web

pytest session scoped fixtures | pythontest - Brian Okken
In this post, I'm going to show a simple example so you can see it in action. A separate file for fixtures, conftest.py....
Read more >
Contextual/Thread-local Sessions — SQLAlchemy 1.4 ...
local() to track Session objects and consider more explicit means of scoping when using application servers which are not based on traditional ...
Read more >
Handling scoped_session across multiple modules with ...
So I have a Pool with worker process. When I call main_script.run() each worker creates a database session inside some_func . My question...
Read more >
Scoped Providers in GraphQL-Modules – The Guild
Every GraphQL-Module creates a ModuleSessionInfo instance in each network request that contains raw Session from the GraphQL Server, ...
Read more >
pytest fixtures: explicit, modular, scalable
Scope : sharing fixtures across classes, modules, packages or session¶. Fixtures requiring network access depend on connectivity and are usually time-expensive ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found