0

I have some sample code below, where I create an object then throw an exception.

import sys

class Abc(object):
    def __init__(self):
        pass

    def __del__(self):
        print('>>>>>>>>>>>>del')
        sys.exit(12)

print('before')
a = Abc()
print('after')

raise Exception('asd')

Output:

before
after
Traceback (most recent call last):
  File "C:\development\test.py", line 13, in <module>
    raise Exception('asd')
Exception: asd
>>>>>>>>>>>>del
Exception ignored in: <bound method Abc.__del__ of <__main__.Abc object at 0x007E2BB0>>
Traceback (most recent call last):
  File "C:\development\aft-system\components\Core\src\python\PythonAPI\sel\aft\tests\regression_tests\exit_code_tests\test.py", line 9, in __del__
SystemExit: 12

As you can see, the destructor is called, but I can't seem to get a debugger in there. I'd like to get access to the exception and change the exit code if possible.

As you can see, the the sys.exit is called, but that throws an exception which is ignored by the current exception.

I should note that I can't wrap this in a try/catch as it's just a library for someone else to use. This scenario is for when an exception happens in the caller or some other library.

Any thoughts?

Eric Fossum
  • 2,395
  • 4
  • 26
  • 50
  • Its not clear what you're trying to do. i'd look up try/except blocks for python. – William Bright Mar 08 '19 at 19:48
  • I'd be very wary of implementing `__del__`. Are you sure you want to? Note, I it is not guaranteed for `__del__` to be called for objects that still exist when the interpreter exits. You are treading on shaky territory here – juanpa.arrivillaga Mar 08 '19 at 19:49
  • Sorry, I added a note at the bottom describing the situation. I can't wrap it in a try/catch, because it's outside of my stack. I'm open to not using a destructor, but I can't think of how to do it. This is a test reporting module and needs to edit the exit code of the script. – Eric Fossum Mar 08 '19 at 19:50
  • what exactly are you trying to do ? – William Bright Mar 08 '19 at 19:51
  • It's not clear to me at all what you are trying to accomplish, and how it is related to `__del__` – juanpa.arrivillaga Mar 08 '19 at 19:52
  • "change the exit code." – Eric Fossum Mar 08 '19 at 19:55
  • What does that have to do with `__del__`? Again, *can you please elaborate on exactly what you are trying to accomplish*? Preferably by editing your question to add additional details. – juanpa.arrivillaga Mar 08 '19 at 19:56
  • @juanpa.arrivillaga the destructor is trying to change the exit code as it's being destroyed. Can you think of another way to do this? There is atexit, but it isn't called during an exception, which is exactly when I need to change it. – Eric Fossum Mar 08 '19 at 19:58
  • Your destructor isn't doing anything except printing. There is nothing in your code snippet about exit codes. This is a classic X-Y problem. *What are you actually trying to accomplish*? – juanpa.arrivillaga Mar 08 '19 at 19:59
  • Ahh, I see what you're asking now. Well, you'd think I can just call sys.exit, but that's an exception and during destruction (from a previous exception) the exit exception will be ignored. – Eric Fossum Mar 08 '19 at 20:01
  • By the way you change the "exit code" by just having something like whatever your program's function is running as its "main" function returns. So just return 99 or whatever code you want inside that function. – William Bright Mar 08 '19 at 20:01
  • @juanpa.arrivillaga I've added an example of using sys.exit. – Eric Fossum Mar 08 '19 at 20:06
  • @WilliamBright - I am writing a library, so I don't have access to the scripts "main" return. – Eric Fossum Mar 08 '19 at 20:07
  • 1
    so in your library you're trying to purposefully break things? What exactly are you trying to do. Still not clear what your intent is. Also if you're not controlling "main" what does it matter how the overall program exits? – William Bright Mar 08 '19 at 20:10
  • @WilliamBright - Correct. As it's a test reporting library, I need to change exit codes based on test results. For example, if a test is skipped that's a 5, 0/1 is pass/fail and 4 is abort (like an exception). This means when something raises an exception, I need to change the exit code to a 4. – Eric Fossum Mar 08 '19 at 20:18
  • this isn't something you would implement it like that. You would call your regular method inside your class and then if something happens, you could raise an error there. Very rarely do you have to go to the destructor, and this isn't a case that calls for that. @EricFossum – William Bright Mar 08 '19 at 20:25
  • I think an acceptable case would be a context `__exit__`. Can I rely on that for exceptions within the context? – Eric Fossum Mar 08 '19 at 20:44

1 Answers1

0

One option is to use a context manager, but that would fundamentally change our API. Seems this question has been asked before and the answer is to override the built-in exception handler.

Setting an exit code for a custom exception in python

My modified test code:

import sys
import traceback

class Abc(object):
    def __init__(self):
        self._original_except_hook = sys.excepthook
        sys.excepthook = Abc.exception_hook

    @staticmethod
    def exception_hook(exc_type, exc_value, trace, *_):
        """Override the built-in Python exception handler."""
        traceback.print_exception(exc_type, exc_value, trace)
        sys.exit(12)

a = Abc()

raise Exception('asd')

Test Output:

PS C:\> python C:\development\test.py ; $LASTEXITCODE
Traceback (most recent call last):
  File "C:\development\test.py", line 17, in <module>
    raise Exception('asd')
Exception: asd
12
PS C:\>
Eric Fossum
  • 2,395
  • 4
  • 26
  • 50