Pythonnet: IDisposable should implement the context manager protocol

Created on 26 Jun 2015  Â·  9Comments  Â·  Source: pythonnet/pythonnet

Pretty self-explanatory :)

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

enhancement

Most helpful comment

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.

All 9 comments

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.

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

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

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.

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.

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

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

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 [email protected]
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
https://github.com/pythonnet/pythonnet/issues/79#issuecomment-188182437.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

satanasss picture satanasss  Â·  9Comments

Mattpdrexel picture Mattpdrexel  Â·  8Comments

lostmsu picture lostmsu  Â·  5Comments

agilevic picture agilevic  Â·  3Comments

denfromufa picture denfromufa  Â·  4Comments