Search code examples
pythonpython-3.xdecoratorwrapperpython-decorators

(Python) Function decorator to pass Playwright Page object to wrapped function


Goal: I am trying to create a function decorator which passes a Playwright Page(playwright.sync_api._generated.Page) object to the wrapped function.

Issue: For most function calls, I would be able to return the value returned by the function call. However, since Playwright necessitates the browser.close() call, I can't simply return the Page object. I am not sure whether the problem is in (1) the function decorator which I have defined, or (2) my usage of the function decorator.

I tried to model my decorator after pytest fixtures. Using pytest, I would do something like this:

@pytest.fixture(scope="module")
def playwright_page():
    with sync_playwright() as play:
        browser = play.chromium.launch()
        page = browser.new_page()
        yield page
        browser.close()

and then

def open_google(playwright_page):
    playwright_page.goto("https://google.com")

Function Decotator:

>>> from playwright.sync_api import sync_playwright
>>> def playwright_page(func):
        def wrapper(*args, **kwargs):
            with sync_playwright() as play:
                browser = play.chromium.launch()
                page = browser.new_page()
                yield page
                browser.close()
        return wrapper

Attempt 1:

>>> @playwright_page
def open_google():
    page.goto("https://google.com")

    
>>> open_google()
<generator object playwright_page.<locals>.wrapper at 0x0000015C5F6CBC10>

Attempt 2:

>>> @playwright_page
    def open_google():
        page = next(page)
        page.goto("https://google.com")

    
>>> open_google()
<generator object playwright_page.<locals>.wrapper at 0x0000015C5FDB7F90>

Solution

  • Instead of trying to yield the Page object, such as for pytest fixtures, I should have been calling func and passing the Page object.

    >>> from playwright.sync_api import sync_playwright
    >>> def playwright_page(func):
            def wrapper():
                with sync_playwright() as play:
                    browser = play.chromium.launch()
                    page = browser.new_page()
                    results = func(page)
                    browser.close()
                    return results
            return wrapper
    
    
    >>> @playwright_page
        def open_google(page):
            page.goto("https://google.com")