How to get an object without an attribute

Suppose we are trying to access a nonexistent attribute:

>>> {'foo': 'bar'}.gte('foo') # well, I meant "get"! 

Pythons AttributeError has an args attribute with a string containing the final error message: 'dict' object has no attribute 'gte'

Using inspect and / or traceback with sys.last_traceback , is there a way to get a real dict object?

 >>> offending_object = get_attributeerror_obj(sys.last_traceback) >>> dir(offending_object) [... 'clear', 'copy', 'fromkeys', 'get', # ah, here it is! 'items', ...] 

Edit: since the cat still got out of the bag, I shared my findings and code (please do not allow this and do not send it to PyPI, please;))

AttributeError created here , which shows that theres is not explicitly referencing the source object.

Here's a code with the same placeholder function:

 import sys import re import difflib AE_MSG_RE = re.compile(r"'(\w+)' object has no attribute '(\w+)'") def get_attributeerror_obj(tb): ??? old_hook = sys.excepthook def did_you_mean_hook(type, exc, tb): old_hook(type, exc, tb) if type is AttributeError: match = AE_MSG_RE.match(exc.args[0]) sook = match.group(2) raising_obj = get_attributeerror_obj(tb) matches = difflib.get_close_matches(sook, dir(raising_obj)) if matches: print('\n\nDid you mean?', matches[0], file=sys.stderr) sys.excepthook = did_you_mean_hook 
+7
python exception
source share
2 answers

This is not the answer you want, but I'm sure you cannot ... at least not with sys.excepthook . This is because link counts decrease as the frame unwinds, so it is ideal for garbage collected before sys.excepthook is sys.excepthook . In fact, this is what happens in CPython:

 import sys class X: def __del__(self): print("deleting") def error(): X().wrong old_hook = sys.excepthook def did_you_mean_hook(type, exc, tb): print("Error!") sys.excepthook = did_you_mean_hook error() #>>> deleting #>>> Error! 

However, this is not always the case. Because the exception object points to a frame if your code looks like this:

 def error(): x = X() x.wrong 

x cannot be collected yet. x belongs to the frame, and the frame is alive. But since I have already proven that there is no explicit reference to this object, it is never obvious what to do. For example,

 def error(): foo().wrong 

may or may not have an object that survived, and the only possible way to find out is to run foo ... but even then you have problems with side effects.

No, It is Immpossible. If you don't mind going to any questions, you will probably end up having to rewrite AST for download (akin to FuckIt.py ). You do not want to do this.


My suggestion would be to try using linter to get the names of all known classes and their methods. You can use this to reverse engineer the trace string to get the class and the wrong method, and then run a fuzzy match to find the sentence.

+1
source share

Adding my 2 cents while I was successfully (so far) trying to do something like this for DidYouMean-Python .

The trick here is that it is almost the case when the error message contains enough information to conclude what you really had in mind. Indeed, it is important here that you tried to call gte on a dict object: you need a type, not the object itself.

If you wrote {'foo': 'bar'}.get('foob') , the situation would be much more complicated, and I would be happy to know if anyone has a solution.

Step one

Make sure you handle the AttributeError attribute (using the first argument to hook).

Second step

Extract the appropriate information from the message (using the second argument). I did this with a regex. Note that this exception can take several forms depending on the version of Python, the object you are calling the method on, etc.

So far my regular expression is: "^'?(\w+)'? (?:object|instance) has no attribute '(\w+)'$"

Third step

Get an object of type that matches the type ('dict' in your case) so you can call dir() on it. A dirty solution will simply use eval(type) , but you can make it better and cleaner by reusing the information in the trace (the third argument of your hook): the last trace element contains the frame in which the exception occurred, and in this frame, the type was defined correctly (either as local, global, or inline).

Once you have an object of type, you just need to call dir() on it and extract the most suitable sentence for you.

Please let me know if you need detailed information about what I have done.

+1
source share

All Articles