Giter VIP home page Giter VIP logo

Comments (4)

Tinche avatar Tinche commented on May 19, 2024

Hello!

You're basically correct in your assessment. The event_loop fixture is really simple, and that's so it can be overridden easily and with basically no knowledge of even pytest. Personally I think wanting to use a faster loop, like uvloop, is a really common scenario even for beginners.

The fact of the matter is, if your test isn't marked pytest.mark.asyncio it's not a pytest-asyncio test. It's just a normal test. You happen to be using a fixture we define. Without the marker, no special behavior will trigger and that's by design.

Now, as for the event loop policy. I've considered making it a fixture but went with a pytest fixture hook wrapper instead. This hook wrapper is, again, only set to execute if the test is marked asyncio. This spares me explaining to users that, sometimes, if they want to have their fixtures depend on the event loop or want to invoke event_loop.run_until_complete themselves, their fixtures/tests really need to depend on the event_loop_policy fixture instead.

Having the event_loop fixture depend on another fixture, like an event_loop_policy_status fixture is interesting but I think ultimately too complex.

I'm basically happy with this arrangement. Your use case almost doesn't require pytest-asyncio at all, you can get away with just defining two fixtures which are both basically one-liners. I'd suggest you just create an autouse fixture to set the event loop into the policy.

I won't say no to improving the docs, of course. :)

from pytest-asyncio.

AndreLouisCaron avatar AndreLouisCaron commented on May 19, 2024

Your use case almost doesn't require pytest-asyncio at all,

Except most tests in this project use your asyncio maker. I have a few tests that run without it to check for regressions in my CLI and these tests cannot use the marker (as previously explained, this would require .run_until_complete() to be reentrant).

You happen to be using a fixture we define. Without the marker, no special behavior will trigger and that's by design.

Using the fixture without the marker leads to hard to debug issues related to having two different event loops active at the same time in the same context. That's a feature?

This spares me explaining to users that, sometimes, if they want to have their fixtures depend on the event loop or want to invoke event_loop.run_until_complete themselves, their fixtures/tests really need to depend on the event_loop_policy fixture instead.

I'm not sure I follow you. What I proposed is essentially having the original event_loop fixture from 0.3.0, but to have it depend on a second fixture called forbid_global_event_loop.

@pytest.fixture(scope='session')
def forbid_global_event_loop():
    return False  # Can be True, I really don't mind.

# Not tested :-)
@pytest.yield_fixture(scope='session')
def event_loop(forbid_global_event_loop):
    loop = asyncio.new_event_loop()
    if forbid_global_event_loop:
        asyncio.set_event_loop_policy(ForbiddenEventLoopPolicy())
    yield loop
    loop.close()

That way, a project can simply put this in their conftest.py to decide whether they want to allow their code to use the default event loop or not:

@pytest.fixture
def forbid_global_event_loop():
    return True

The event_loop fixture is really simple, and that's so it can be overridden easily [...] Personally I think wanting to use a faster loop, like uvloop, is a really common scenario even for beginners.

This, I wholeheartedly agree with. I need to support Windows a lot and since the default SelectorEventLoop for Windows is a really inconvenient default, all my projects need to switch to ProactorEventLoop as soon as I write the first test for anything that uses asyncio. Rewriting the entire event_loop just to pick the event loop class would be a PITA.

Maybe this requires more thinking, but my first reflex would be to allow people to provide their own event loop factory without having to rewrite the event_loop fixture. You can extend my proposal above to allow people to supply their custom event loop class with a one-liner like this:

@pytest.fixture
def new_event_loop():
    return UVLoop()  # Whatever.

And then reference this from your event_loop fixture to create the new event loop instead of calling asyncio.new_event_loop().

This way:

  1. you keep the one-liner event loop override;
  2. @asvetlov gets an easy way to forbid global event loop access for his entire project with a one-liner; and
  3. I get to keep your event_loop fixture even for my tests that don't use the marker.

from pytest-asyncio.

Tinche avatar Tinche commented on May 19, 2024

There already is an event loop factory fixture. It's just called event_loop. :) I believe mutating global state is a tricky thing; the event_loop fixture just makes an event loop for you and hands it over; closes it afterwards.

I considered your idea while I was preparing the 0.5 release, but I find the extra fixtures inelegant. (Especially fixtures that yield configuration.) Anyway, I'm not interested in discussing the subtleties of API design. What we can discuss is how to make the current design work for some of these cases.

For example, the issue of repeating yourself a lot to forbid the global event loop could be solved by http://doc.pytest.org/en/latest/example/markers.html#marking-whole-classes-or-modules. I actually thought that would work out of the box, but alas, no: pytest-dev/pytest#1943

Your problem is that you can't apply the marker to a non-coroutine. So maybe we could make it so the plugin only runs coroutines in the event loop, or make a new marker that would do so.

from pytest-asyncio.

AndreLouisCaron avatar AndreLouisCaron commented on May 19, 2024

Your problem is that you can't apply the marker to a non-coroutine. So maybe we could make it so the plugin only runs coroutines in the event loop, or make a new marker that would do so.

Yeah, I guess that would work, but I find it gives a quirky API. I'll end up writing my own pytest plug-in that behaves the way I want it to.

from pytest-asyncio.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.