Get class and attribute names from AttributeError - python

How do I get the class and missing attribute from AttributeError, e.g.
when AttributeError says: 'NoneType' object has not attribute a, I would like to get "NoneType" and "a".

Looks like the only thing you can retrieve from an AttributeError is the string with the error message:
try:
str.s
except AttributeError as err:
error_message, = err.args
print("Error message:", error_message)
raise

For getting the type information out of an AttributeError, you could probably use regex, since you know the format of the error message:
import re
try:
None.attr
except AttributeError as e:
matches = re.match(r"'([^']*)' object has no attribute '([^']*)'", str(e))
obj_type = matches.group(1)
attr_name = matches.group(2)
print(f"Object type: {obj_type}, attribute name: {attr_name}")
# Object type: NoneType, attribute name: attr

import re
try:
# access attribute
except AttributeError as e:
obj_type, attr_name = re.match(r"\'([a-zA-Z0-9\_]+)\' object has no attribute \'([a-zA-Z0-9\_]+)\'", str(e)).groups()
First cast the error into text with str(e)
Then, using regular expression pattern read the object type and the name of the attribute you're trying to access. The groups() method will return all the captured groups from the regex which are marked with parenthesis.

Related

How to know what function throws the exception in Python

I have a python script over 2000 lines and it's through the below exception on the production server and I'm not able to reproduce the issue locally to debug it and I don't know where it comes from.
Exception TypeError: TypeError("argument of type 'NoneType' is not iterable",) in <bound method Popen3.__del__ of <popen2.Popen3 instance at 0x7fccba7b65f0>> ignored
Exception TypeError: TypeError("argument of type 'NoneType' is not iterable",) in <bound method Popen3.__del__ of <popen2.Popen3 instance at 0x7fccba7b62d8>> ignored
Exception TypeError: TypeError("argument of type 'NoneType' is not iterable",) in <bound method Popen3.__del__ of <popen2.Popen3 instance at 0x7fccba824ef0>> ignored
Exception TypeError: TypeError("argument of type 'NoneType' is not iterable",) in <bound method Popen3.__del__ of <popen2.Popen3 instance at 0x7fccba824f80>> ignored
Is there a way to make the interpreter print the trace for the exception as Java does? To be able to know what is throwing this exception.
The simplest way is to use traceback.print_exc() in the except block:
try:
1[0] # raises
except TypeError:
traceback.print_exc()
raise

Retrieve details from AttributeError object in Python

I am enumerating some objects in a list, which may or may not have certain properties. If a property does not exists, I get the AttributeError. What I want to do is to catch the exception object and retrieve the specific property that causes the error and set it to an empty string. I don't see any method in the AttributeError object to retrieve the said attribute.
Partial code here:
import wmi
c = wmi.WMI ()
for account in c.Win32_Account():
try:
print(f"Name: {account.Name}, FullName: {account.FullName}, LocalAccount: {account.LocalAccount}, Domain: {account.Domain}")
except AttributeError as error:
# How do I retreive the attribute in question from the exception object?
Per original post, you want to "retrieve the specific property that causes the error and set it to an empty string".
if you just wanted to print the string use getattr:
https://docs.python.org/3/library/functions.html#getattr
import wmi
c = wmi.WMI ()
for account in c.Win32_Account():
print(f"Name: {getattr(account, 'Name', "")}, FullName: {getattr(account, 'FullName', "")}, LocalAccount: {getattr(account, 'LocalAccount', "")}, Domain: {getattr(account, 'Domain', "")}")
if you want to actually overwrite the missing values use hasattr and setattr:
for account in c.Win32_Account():
for attr in ['Name', 'FullName', 'LocalAccount', 'Domain']:
if not hasattr(account, attr):
setattr(account, attr, "")
Every Exception object stores its arguments in the .args property. The argument to an AttributeError object is a string that contains the object on which the property access is being used and the property being accessed.
The format of this message looks like-
('|")object_name('|") object has no attribute ('|")property_name('|")
Where ('|") means "either matching double quotes or single quotes"
You can extract both the object name and property name using this regex-
(?:\'|")(\w+)(?:\'|")
So the final implementation would look like-
import wmi
import re
c = wmi.WMI ()
for account in c.Win32_Account():
try:
print(f"Name: {account.Name}, FullName: {account.FullName}, LocalAccount: {account.LocalAccount}, Domain: {account.Domain}")
except AttributeError as error:
property_name = re.findall(r'(?:\'|")(\w+)(?:\'|")', error.args[0])[-1]

Python TypeError when printing traceback of AttributeError using traceback.print_exc()

A reproducible example:
import traceback
X = None
try:
X.text
except (TypeError, AttributeError) as e:
traceback.print_exc(e)
This will raise an error at traceback.print_exc(e):
TypeError: '>=' not supported between instances of 'AttributeError' and 'int'
Any suggestion why this happens?
print_exc doesn't take the exception object as an argument, it uses sys.exc_info() to obtain exception information. When you're passing it e, it's interpreting it as a positional argument for limit which expects a type int. I believe if you just remove the argument you'll get the result you're looking for.
traceback.print_exc documentation
Based on the documentation : Python Docs - traceback module
The first argument to traceback.print_exc isn't the exception, it is a depth limit of how many deep the traceback goes. You are hitting an exception within the traceback module itselse, since it expects the first argument to be a limit.
Your code needs to be :
import traceback
X = None
try:
X.text
except (TypeError, AttributeError) as e:
traceback.print_exc()
The exception data is kept as a thread global in sys.exc_info() which is what traceback.print_exc() uses.

handling exception from python gammu library

I'm using python gammu library for sending sms. Sometimes something is wrong and I would like to handle exception. Descritpion of Exceptions is here: https://wammu.eu/docs/manual/python/exceptions.html#module-gammu.exception
I have a problem with getting and returning errors from such situations. I've printed:
print(sys.exc_info())
It has result:
(<class 'gammu.ERR_UNKNOWN'>, ERR_UNKNOWN({'Text': 'Nieznany błąd.', 'Where': 'SendSMS', 'Code': 27}), <traceback object at 0x740a6cd8>)
If i assign:
error_obj = sys.exc_info()
How can I get from it: Text, Code, and type ERROR(here is ERR_UKNOWN)?
I will grateful for help.
cls, exception, _ = sys.exc_info()
text = exception['Text'] # or exception.Text ?
code = exception['Code'] # or exception.Code ?
print(cls, text, code)
Also take a look at traceback module:
import traceback
try:
1/0
except ArithmeticError as e:
traceback.print_exc()
You should be able to use the args on the exception to get to the Text:
print(error_obj.args)
error_obj.args[0]['Text']

Python : Another 'NoneType' object has no attribute error

For a newbie exercise , I am trying to find the meta tag in a html file and extract the generator so I did like this :
Version = soup.find("meta", {"name":"generator"})['content']
and since I had this error :
TypeError: 'NoneType' object has no attribute '__getitem__'
I was thinking that working with exception would correct it, so I wrote :
try: Version = soup.find("meta", {"name":"generator"})['content']
except NameError,TypeError:
print "Not found"
and what I got is the same error.
What should I do then ?
The soup.find() method did not find a matching tag, and returned None.
The [...] item access syntax looks for a __getitem__ method, which is the source of the AttributeError here:
>>> None[1]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object has no attribute '__getitem__'
Test for None explicitly:
Version = soup.find("meta", {"name":"generator"})
if Version is not None:
Version = Version['content']
else:
print "Not found"
Your exception handling would work too, provided you use parenthesis to group the exceptions:
try:
Version = soup.find("meta", {"name":"generator"})['content']
except (NameError, TypeError):
print "Not found"
Without parenthesis you are telling Python to catch NameError exceptions and assign the resulting exception object to the local name TypeError. This except Exception, name: syntax has been deprecated because it can lead to exactly your situation, where you think you are catching two exceptions.
However, your code here should not throw a NameError exception; that'd be a separate problem better solved by instantiating your variables properly; the following would work just as well here:
try:
Version = soup.find("meta", {"name":"generator"})['content']
except TypeError:
# No such meta tag found.
print "Not found"
Try this:
content = None
Version = soup.find("meta", {"name":"generator"})
if Version:
content = Version.get('content')
#or even
#Version = Version.get('content')
else:
print "Not found"
The issue is, soup.find returns a None if match was not found, and extracting data out of None results in error.

Categories