For the 1st form:
def get_playwright():
with sync_playwright() as playwright:
yield playwright
print(get_playwright()) # <generator object get_playwright at 0x108aac580>
That is expected because get_playwright
is a generator, which returns a generator iterator, which you have to call next(...)
on to get each yielded value from the iterator.
Consider a simpler, non-playwright example:
In [14]: def generate_nums():
...: for num in range(10):
...: yield num
...:
In [15]: nums = generate_nums()
In [16]: nums
Out[16]: <generator object generate_nums at 0x11115e6d0>
In [17]: next(nums)
Out[17]: 0
In [18]: next(nums)
Out[18]: 1
In [19]: next(nums)
Out[19]: 2
For more examples, see Understanding generators in Python.
Since your get_playwright
returns an iterator, you need to call next()
once to get the actual object:
from playwright.sync_api import sync_playwright
def get_playwright():
with sync_playwright() as playwright:
yield playwright
playwright_generator = get_playwright()
print(playwright_generator) # <generator object get_playwright at 0x104031580>
playwright = next(playwright_generator)
print(playwright) # <playwright._impl._playwright.Playwright object at 0x1041aabb0>
For the 2nd form:
@pytest.fixture()
def get_playwright():
with sync_playwright() as playwright:
yield playwright
def test(get_playwright):
print(get_playwright)
It should be the same case, but it's just that pytest automatically calls next()
on the fixture value if it's a generator. I could not find documentation for this behavior from the pytest docs, but it was mentioned by one of the pytest author's/maintainer's in a different answer:
Here's roughly the execution here
- pytest notices your fixture is used for the test function
- pytest calls the fixture function
- since it is a generator, it returns immediately without executing code
- pytest notices it is a generator, calls
next(...)
on it
- this causes the code to execute until the
yield
and then "pausing". you can think of it kind of as a co-routine
...
- pytest then executes your test function
...which is probably why the value passed to your test function is already the next
-ed value, the playwright object.