Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I create an Exception in Python minus the last stack frame?

Not sure how possible this is, but here goes:

I'm trying to write an object with some slightly more subtle behavior - which may or may not be a good idea, I haven't determined that yet.

I have this method:

def __getattr__(self, attr):                                                                                                      
    try:                                                                       
        return self.props[attr].value                                          
    except KeyError:                                                           
        pass #to hide the keyerror exception                                   

    msg = "'{}' object has no attribute '{}'"                                  
    raise AttributeError(msg.format(self.__dict__['type'], attr)) 

Now, when I create an instance of this like so:

t = Thing()
t.foo

I get a stacktrace containing my function:

Traceback (most recent call last):
  File "attrfun.py", line 23, in <module>
    t.foo
  File "attrfun.py", line 15, in __getattr__
    raise AttributeError(msg.format(self._type, attr))
AttributeError: 'Thing' object has no attribute 'foo'

I don't want that - I want the stack trace to read:

Traceback (most recent call last):
  File "attrfun.py", line 23, in <module>
    t.foo
AttributeError: 'Thing' object has no attribute 'foo'

Is this possible with a minimal amount of effort, or is there kind of a lot required? I found this answer which indicates that something looks to be possible, though perhaps involved. If there's an easier way, I'd love to hear it! Otherwise I'll just put that idea on the shelf for now.

like image 688
Wayne Werner Avatar asked Nov 18 '14 11:11

Wayne Werner


1 Answers

You cannot tamper with traceback objects (and that's a good thing). You can only control how you process one that you've already got.

The only exceptions are: you can

  • substitute an exception with another or re-raise it with raise e (i.e make the traceback point to the re-raise statement's location)
  • raise an exception with an explicit traceback object
  • remove outer frame(s) from a traceback object by accessing its tb_next property (this reflects a traceback object's onion-like structure)

For your purpose, the way to go appears to be the 1st option: re-raise an exception from a handler one level above your function.

And, I'll say this again, this is harmful for yourself or whoever will be using your module as it deletes valuable diagnostic information. If you're dead set on making your module proprietary with whatever rationale, it's more productive for that goal to make it a C extension.

like image 51
ivan_pozdeev Avatar answered Oct 01 '22 17:10

ivan_pozdeev