Skip to content

page fixture: You cannot call this from an async context - use a thread or sync_to_async. #46

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

Closed
guettli opened this issue Mar 19, 2021 · 2 comments

Comments

@guettli
Copy link

guettli commented Mar 19, 2021

I get this Exception, if I try to use the page fixture together with the live_server fixture of "pytest-django".


(lala-env) guettli@yoga15:~/projects/lala-env/src/lala$ pytest -k chili
============================================================================== test session starts ===============================================================================
platform linux -- Python 3.8.5, pytest-6.2.0, py-1.10.0, pluggy-0.13.1
django: settings: mysite.settings (from env)
rootdir: /home/guettli/projects/lala-env/src/lala, configfile: pytest.ini
plugins: django-4.1.0, playwright-0.0.12, base-url-1.4.2
collected 61 items / 60 deselected / 1 selected                                                                                                                                  

lala/playwright/create_testdata_add_address_order_chili_test.py E

===================================================================================== ERRORS =====================================================================================
______________________________________________________________________ ERROR at setup of test_it[chromium] _______________________________________________________________________

self = <django.db.backends.postgresql.base.DatabaseWrapper object at 0x7f987e645e80>

    @contextmanager
    def _nodb_cursor(self):
        """
        Return a cursor from an alternative connection to be used when there is
        no need to access the main database, specifically for test db
        creation/deletion. This also prevents the production database from
        being exposed to potential child threads while (or after) the test
        database is destroyed. Refs #10868, #17786, #16969.
        """
        conn = self.__class__({**self.settings_dict, 'NAME': None}, alias=NO_DB_ALIAS)
        try:
>           with conn.cursor() as cursor:

../../lib/python3.8/site-packages/django/db/backends/base/base.py:620: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

args = (<django.db.backends.postgresql.base.DatabaseWrapper object at 0x7f9877798160>,), kwargs = {}, event_loop = <_UnixSelectorEventLoop running=True closed=False debug=False>

    @functools.wraps(func)
    def inner(*args, **kwargs):
        if not os.environ.get('DJANGO_ALLOW_ASYNC_UNSAFE'):
            # Detect a running event loop in this thread.
            try:
                event_loop = asyncio.get_event_loop()
            except RuntimeError:
                pass
            else:
                if event_loop.is_running():
>                   raise SynchronousOnlyOperation(message)
E                   django.core.exceptions.SynchronousOnlyOperation: You cannot call this from an async context - use a thread or sync_to_async.

../../lib/python3.8/site-packages/django/utils/asyncio.py:24: SynchronousOnlyOperation

During handling of the above exception, another exception occurred:

request = <SubRequest '_live_server_helper' for <Function test_it[chromium]>>

    @pytest.fixture(autouse=True, scope="function")
    def _live_server_helper(request):
        """Helper to make live_server work, internal to pytest-django.
    
        This helper will dynamically request the transactional_db fixture
        for a test which uses the live_server fixture.  This allows the
        server and test to access the database without having to mark
        this explicitly which is handy since it is usually required and
        matches the Django behaviour.
    
        The separate helper is required since live_server can not request
        transactional_db directly since it is session scoped instead of
        function-scoped.
    
        It will also override settings only for the duration of the test.
        """
        if "live_server" not in request.fixturenames:
            return
    
>       request.getfixturevalue("transactional_db")

../../lib/python3.8/site-packages/pytest_django/fixtures.py:440: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../lib/python3.8/site-packages/pytest_django/fixtures.py:105: in django_db_setup
    db_cfg = setup_databases(
../../lib/python3.8/site-packages/django/test/utils.py:170: in setup_databases
    connection.creation.create_test_db(
../../lib/python3.8/site-packages/django/db/backends/base/creation.py:55: in create_test_db
    self._create_test_db(verbosity, autoclobber, keepdb)
../../lib/python3.8/site-packages/django/db/backends/base/creation.py:186: in _create_test_db
    with self._nodb_cursor() as cursor:
/usr/lib/python3.8/contextlib.py:113: in __enter__
    return next(self.gen)
../../lib/python3.8/site-packages/django/db/backends/postgresql/base.py:301: in _nodb_cursor
    with super()._nodb_cursor() as cursor:
/usr/lib/python3.8/contextlib.py:113: in __enter__
    return next(self.gen)
../../lib/python3.8/site-packages/django/db/backends/base/base.py:623: in _nodb_cursor
    conn.close()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

args = (<django.db.backends.postgresql.base.DatabaseWrapper object at 0x7f9877798160>,), kwargs = {}, event_loop = <_UnixSelectorEventLoop running=True closed=False debug=False>

    @functools.wraps(func)
    def inner(*args, **kwargs):
        if not os.environ.get('DJANGO_ALLOW_ASYNC_UNSAFE'):
            # Detect a running event loop in this thread.
            try:
                event_loop = asyncio.get_event_loop()
            except RuntimeError:
                pass
            else:
                if event_loop.is_running():
>                   raise SynchronousOnlyOperation(message)
E                   django.core.exceptions.SynchronousOnlyOperation: You cannot call this from an async context - use a thread or sync_to_async.

../../lib/python3.8/site-packages/django/utils/asyncio.py:24: SynchronousOnlyOperation
============================================================================ short test summary info =============================================================================
ERROR lala/playwright/create_testdata_add_address_order_chili_test.py::test_it[chromium] - django.core.exceptions.SynchronousOnlyOperation: You cannot call this from an async ...
==


It works, if I create the page object like this:

def test_it(live_server):
    os.environ['DEBUG']='pw:api'
    with sync_playwright() as playwright:
        run_test_id(live_server, playwright)

def run_test_id(live_server, playwright):
    browser = playwright.webkit.launch(headless=False)
    context = browser.new_context()
    page = context.new_page()
    page.goto(live_server.url)

Any hint how to solve this?

@mxschmitt
Copy link
Member

Could you try setting the environment variable DJANGO_ALLOW_ASYNC_UNSAFE to 1? That should fix it.

@guettli
Copy link
Author

guettli commented Mar 19, 2021

@mxschmitt thank you, this works, although I am not super happy with this. I don't want to allow unsafe async by default, but that is a different topic. I close this, since it is solved for me. Feel free to reopen.

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

No branches or pull requests

2 participants