4
votes

I'm attempting to wrap a poorly written Python module (that I have no control of) in a class. The issue is that if I don't explicitly call that module's close function then the python process hangs on exit, so I've attempted to wrap the module with a class that has a del method, however the del method does not seem to be called on exceptions.

Example:

class Test(object):
    def __init__(self):
        # Initialize the problematic module here
        print "Initializing"

    def __del__(self):
        # Close the problematic module here
        print "Closing"

t = Test()
# This raises an exception
moo()

In this case del is not called and python hangs. I need somehow to force Python to call del immediately whenever the object goes out of scope (like C++ does). Please note that I have no control over the problematic module (i.e. cannot fix the bug that causes this in the first place) and also no control over whoever uses the wrapper class (can't force them to use "with" so I can't use exit either).

Is there any decent way to solve this?

Thanks!

3
Don't use del. This is not C++ or a language built for destructors. The del method really should be gone in Python 3.x, though I'm sure someone will find a use case that makes sense. If you need to use del, be aware of the basic limitations per docs.python.org/reference/datamodel.htmlharshil9968
Wrap it with a context manager?jonrsharpe
As I said, I have no control over whoever uses the class. I can't force them to use "with".Dan
@harshil9968 no reason not to call del. Its behavior is deterministic. You just need to be aware of how it works. But, in the context of this question, it won't work as expected :)ivarec

3 Answers

4
votes

If you want some resource to be released on an exception, think about __enter__ + __exit__ paradigm.

class Test(object):
    def __enter__(self):
        pass

    def __exit__(self):
        pass  # Release your resources here

with Test() as t:
    moo()

When the execution goes into the 'with' block, the method __enter__() of 't' is called, and then it leaves the block due to either normal flow, or an exception, the method __exit__() of 't' is called.

1
votes

A possible solution is to use sys.excepthook, which allows you to introduce custom login to the global exception handler. You can add some code there to close your module's leftovers.

0
votes

Please find details below :

class Test:
    def __init__(self):
        print('cons')
    
    def __del__(self):
        print('des')

If we add object of class Test in some global dict and clear that dict once your functionality is completed. It will call destructor

ctx = {}
def a():
    ctx['ao'] = Test()
    raise 1/0

a()

# cons
# Traceback (most recent call last):
#   File "<stdin>", line 1, in <module>
#   File "<stdin>", line 3, in a
# ZeroDivisionError: integer division or modulo by zero

If we release old content of ctx and assign new value, destructor is called

ctx  = {}
# des