Skip to content

IDisposable should implement the context manager protocol #79

Open

Description

@filmor

Pretty self-explanatory :)

Since it's currently not possible to monkey-patch interfaces, this can't be implemented in pure Python.

Activity

  1. tonyroberts commented on Jun 26, 2015

    @tonyroberts
    Contributor

    Sounds like a good idea, and should be pretty easy to implement.

    I think it would just be a case of checking if a type implements IDisposable in ClassManager.GetClassInfo (classmanager.cs) and adding the enter and exit methods. Might need a new subclass of MethodInfo too, since exit and Dispose have different signatures.

  2. filmor commented on Jun 26, 2015

    @filmor
    MemberAuthor

    Oh, nice hint, I'll have a look.

  3. filmor commented on Jun 26, 2015

    @filmor
    MemberAuthor

    Doesn't it make more sense to implement this like IEnumerable is implemented, in classbase.cs?

  4. tonyroberts commented on Jun 27, 2015

    @tonyroberts
    Contributor

    Iterators have a tp_iter pointer in the PyTypeObject struct, which is what is implemented in ClassBase for IEnumerable. There's no equivalent for context managers (unless I've missed something), so I think the enter and exit methods have to be in the class' or object's dict. That's why I was thinking constructing these methods in GetClassInfo would make sense.

  5. den-run-ai commented on Jan 30, 2016

    @den-run-ai
    Contributor
  6. filmor commented on Feb 22, 2016

    @filmor
    MemberAuthor

    It is, yes. I currently use a simple wrapper function for this:

    """Wrapper function to help dealing with IDisposable classes."""
    
    from inspect import isclass, isfunction
    from contextlib import contextmanager
    
    __all__ = ['disposable']
    
    @contextmanager
    def disposable(obj_or_class, *args, **kwargs):
        """Contextmanager wrapper around IDisposables."""
        if isclass(obj_or_class) or isfunction(obj_or_class):
            obj = obj_or_class(*args, **kwargs)
        else:
            obj = obj_or_class
    
        if hasattr(obj, '__enter__') and hasattr(obj, '__exit__'):
            # Already a contextmanager, skip
            return obj
    
        if not hasattr(obj, 'Dispose') or not callable(obj.Dispose):
            # Likely not IDisposable, currently isinstance doesn't work for
            # interfaces so we have to check that in this explicit way
            return obj
    
        try:
            yield obj
        finally:
            obj.Dispose()
    
    

    This allows me to use something like

    with disposable(dbConnection):
        bla
    

    Since IDisposable is so tied into .NET itself by the using keyword it makes sense to forward this functionality directly.

  7. den-run-ai commented on Feb 23, 2016

    @den-run-ai
    Contributor

    @filmor @tonyroberts this should definitely go into advanced examples!

  8. filmor commented on Feb 24, 2016

    @filmor
    MemberAuthor

    @tonyroberts How exactly would I add a method from C#? Hooking into the attribute resolution feels wrong ...

  9. tonyroberts commented on Feb 24, 2016

    @tonyroberts
    Contributor

    You could add it to the class dict. That's probably the best way, and I
    that's how the normal methods are added I seem to remember.

    On Wed, Feb 24, 2016 at 10:29 AM Benedikt Reinartz notifications@github.com
    wrote:

    @tonyroberts https://github.com/tonyroberts How exactly would I add a
    method from C#? Hooking into the attribute resolution feels wrong ...

    —
    Reply to this email directly or view it on GitHub
    #79 (comment).

  10. awa5114 commented on Mar 23, 2025

    @awa5114

    It's been about a decade. Has this been addressed yet?

  11. den-run-ai commented on Mar 23, 2025

    @den-run-ai
    Contributor

    @awa5114 i took a stab at this with claude code, looks reasonable:

    #2568

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions