playwright-python icon indicating copy to clipboard operation
playwright-python copied to clipboard

[Bug]: Type Hinting for BrowserContext.__aexit__ Incompatible with AbstractAsyncContextManager

Open nva14 opened this issue 7 months ago • 0 comments

Version

1.52

Steps to reproduce

In Playwright v1.52.0, the effective type signature for playwright.async_api.BrowserContext.__aexit__ does not seem to mark its exception-related parameters (exc_type, exc_val, traceback) as Optional (e.g., Type[BaseException] | None).

This causes type checking issues with static analyzers like Pylance when BrowserContext instances are used with constructs expecting typing.AbstractAsyncContextManager, such as contextlib.AsyncExitStack().enter_async_context().

Pylance Inferred Signature:

(method) def __aexit__(
    exc_type: type[BaseException],
    exc_val: BaseException,
    traceback: TracebackType
) -> Coroutine[Any, Any, None]

Expected behavior

for AbstractAsyncContextManager compatibility:

(method) async def __aexit__(
    self,
    exc_type: type[BaseException] | None,
    exc_val: BaseException | None,
    traceback: TracebackType | None
) -> Coroutine[Any, Any, bool | None] # Or just None for return

Actual behavior

Static type checkers report complaints because the non-optional parameters are incompatible with the protocol, which expects None to be passed for these arguments on normal context exit.

I'm currently using typing.cast(AsyncContextManager[BrowserContext], browser_context_instance) allows type checkers to proceed.

Additional context

Reproducible example:

import asyncio
from contextlib import AsyncExitStack
from playwright.async_api import async_playwright, BrowserContext

async def main():
    async with AsyncExitStack() as stack:
        pw_manager = async_playwright()
        playwright = await stack.enter_async_context(pw_manager)
        browser_ctx_instance: BrowserContext = await playwright.firefox.launch_persistent_context()
        await stack.enter_async_context(browser_ctx_instance) # <-- Pylance complaint here

        print("Context entered")
        # ...
        await browser.close() # clean up browser launched outside stack for this example

# asyncio.run(main())

Environment

- Operating System: Debian 12
- CPU: [arm64]
- Browser: [All, Chromium, Firefox, WebKit]
- Python Version: [3.13]
- Other info: I'm using DevContainer in VS Code with Pylance. It's on macOS but effective OS is Debian because i'm running image based on `mcr.microsoft.com/devcontainers/python:3-bookworm`

nva14 avatar May 18 '25 08:05 nva14