Skip to content
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

Assorted issues with context managers #9694

Open
mikeshardmind opened this issue Jan 11, 2025 · 0 comments
Open

Assorted issues with context managers #9694

mikeshardmind opened this issue Jan 11, 2025 · 0 comments
Labels
bug Something isn't working

Comments

@mikeshardmind
Copy link

mikeshardmind commented Jan 11, 2025

Describe the bug

Context manager handling is inconsistent, and where issues with it are detected, the error messages do not correctly identify the root cause

Code or Screenshots

Code sample in pyright playground

import asyncio

class WorkingExample:

    async def __aenter__(self) -> None:  ...
    async def __aexit__(self, *dont_care: object) -> None:  ...
    def __enter__(self) -> None:  ...
    def __exit__(self, *dont_care: object) -> None:  ...


class AsyncInvisiblyBrokenExample:
    async def __aenter__(self) -> None:  ...
    def __aexit__(self, *dont_care: object) -> None:  ...  # Ideally, this should be an error too, incompatible with data model
    def __enter__(self) -> None:  ...
    def __exit__(self) -> None:  ...  # Ideally, this should be an error too, incompatible with data model


class VisiblyBrokenExample:
    def __aenter__(self) -> None:  ...  # Ideally, this should be an error too, incompatible with data model
    def __aexit__(self, *dont_care: object) -> None:  ...  # Ideally, this should be an error too, incompatible with data model
    def __enter__(self) -> None:  ...
    def __exit__(self) -> None:  ...

class AlsoInVisiblyBroken:
    def __enter__(self) -> None:  ...



if __name__ == "__main__":
    
    works = WorkingExample()
    visibly_broken = VisiblyBrokenExample()
    async_invisbly_broken = AsyncInvisiblyBrokenExample()

    async def amain() -> None:
        async with works:
            ...
        async with visibly_broken:
            # pyright detects None is not Awaitable (correctly identified issue)
            # however the error message is incorrect, as it claims `__await__` isn't present
            ...
        async with async_invisbly_broken:
            # pyright does not detect that `__aexit__` has the wrong type
            ...

    with works:
        with visibly_broken:  # pyright detects this, but the error message is misleading
            # claims AsyncInvisiblyBroken does not implement `__exit__`, when it does, just incorrectly
            # it does not satisfy the runtime requirements of being a context manager as a result,
            # so the error is correct, but the message doesn't identify the actual issue.
            with async_invisbly_broken:  # same as above
                # in addition though, this shows the asymmetery with the async with above
                # not being caught. 
                asyncio.run(amain())

This was discovered while typing some previously private code for public use with N:M concurrency for use with freethreading python builds.

edit: ignore the definition of AlsoInVisiblyBroken, it was there to demonstrate things that ended up redundant and couldd have been removed.

@mikeshardmind mikeshardmind added the bug Something isn't working label Jan 11, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant