How do I throw an exception in Python minus the last stack frame?

Not sure how possible this is, but it says here:

I'm trying to write an object with a little more subtle behavior - which may or may not be a good idea, I haven't decided 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 instantiate this type like so:

t = Thing()
t.foo

      

I get a stack 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 this - I want the stack trace to be 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 minimal effort or does it take a lot? I found this answer , which indicates that something seems possible, although possibly related to it. If there is an easier way, I'd love to hear it! Otherwise, I'll put this idea on the shelf now.

+3


source to share


2 answers


You cannot tamper with trace objects (which is good). You can only control how you handle the one you already have.

The only exceptions are:



For your purpose, the way to go is the 1st option: re-throw the exception from the handler one level above your function.

And I will say it again, this is harmful to yourself or whoever will use your module, as it removes valuable diagnostic information. If you are determined to make your module proprietary with some justification, the C extension is more productive for this purpose.

+1


source


You can get the current frame and any other level using the checker module. For example, this is what I use when I want to know where I am in my code:



from inspect import currentframe

def get_c_frame(level = 0) :
    """
    Return caller frame
    """
    return currentframe(level)

...
def locate_error(level = 0) :
    """
    Return a string containing the filename, function name and line
    number where this function was called.

    Output is : ('file name' - 'function name' - 'line number')
    """
    fi = get_c_frame(level = level + 2)
    return '({} - {} - {})'.format(__file__,
                               fi.f_code,
                               fi.f_lineno)

      

0


source







All Articles