Techno Blender
Digitally Yours.

Python Tracebacks — Explained. A great helper for debugging. | by Soner Yıldırım | Dec, 2022

0 46


Photo by Anne Nygård on Unsplash

We rarely get a script running without any errors on the first try, which is absolutely normal when writing code. The important and sometimes challenging part is to fix these errors.

The process of fixing the errors and making the script work as expected can take many iterations depending on the experience of the programmer and the information we have about the error. Programming languages give us some hints as to what might be causing the error, which is basically what a Python traceback does.

A traceback in Python can be considered as a report that helps us understand and fix a problem in the code. In this article, we will learn what a traceback in Python is, how to read traceback messages to be able to use them more efficiently, and different error types.

A program in Python stops execution when it encounters an error, which can be in the form of a syntax error or exception. Syntax errors occur when the interpreter detects invalid syntax and they are relatively easier to fix.

An example of a syntax error can be an unmatched parenthesis. On the other hand, an exception is raised when the syntax is correct but the program results in an error.

A traceback is a report that helps us understand the reason for an exception. It contains function calls made in the code along with their line numbers so that we are not clueless about the problem causing the code to fail.

Let’s go over a simple example.

The code snippet below creates a function that adds two numbers and multiplies the sum by the first number. Then, it calls the function with arguments 5 and 4. However, 4 is passed as a string so it is actually not a number.

def add_and_multiply(x, y):
return (x + y) * x

add_and_multiply(5, "4")

When this code is executed, Python raises the following exception:

(image by author)

The last line shows the error type along with a brief explanation. The error in this case is a type error caused by an unsupported operand between integers and strings. The plus operator cannot be used for adding a string to an integer so the code results in an exception.

The lines above the last one tell us where the exception occurred in terms of the function name and the line number. The example we have here is very simple but when working on very long scripts or a program with multiple scripts, information about the function names and line numbers is quite helpful for diagnosing and fixing the issue.

The traceback also shows the module and file names, which is highly helpful when working on scripts that import modules from other files or scripts. How the file and module names are shown change slightly depending on your working environment (e.g. terminal or REPL).

For instance, when I save the code snippet above as “sample_script.py” and try to run it in the terminal, I get the following traceback:

Traceback (most recent call last):
File "/Users/sonery/sample_script.py", line 6, in <module>
add_and_multiply(5, "6")
File "/Users/sonery/sample_script.py", line 2, in add_and_multiply
print((x + y) * x)
TypeError: unsupported operand type(s) for +: 'int' and 'str'

In any case, we get an informative lead in traceback messages.

A substantial amount of time in creating efficient programs and maintaining them in production is spent on debugging errors. Hence, it is of crucial importance to make use of Python tracebacks.

Otherwise, it could take hours to find and fix issues, which might have severe consequences if a program is already deployed into production. ​

The most important part of a traceback message is the error type as it gives us hints about what kind of an error causing the script to stop execution.

Let’s go over some of the commonly encountered error types in the traceback messages.

TypeError

Type error occurs when the data type of an object is not compatible with the defined operation. The example we did in the beginning where an integer and a string are added is an example of this error.

AttributeError

In Python, everything is an object with a type such as integer, string, list, tuple, dictionary, and so on. The types are defined using classes, which also have attributes used for interacting with the objects of a class.

Classes can have data attributes and procedural attributes (i.e. methods):

  • Data attributes: What is needed to create an instance of a class
  • Methods (i.e. procedural attributes): How we interact with instances of a class.

Consider we have an object of type list. We can use the append method for adding a new item to a list. If the object does not have the attribute we are trying to use, an attribute error exception is raised.

Here is an example:

mylist = [1, 2, 3, 4, 5]

mylist.add(10)

# output
Traceback (most recent call last):
File "<file>", line 3378, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "<ipython-input-25-4ad0ec665b52>", line 3, in <module>
mylist.add(10)
AttributeError: 'list' object has no attribute 'add'

Since the list class does not have an attribute called “add”, we get a traceback showing an attribute error.

ImportError and ModuleNotFoundError

Python has a huge selection of third-party libraries (i.e. modules), which makes it possible to complete a lot of tasks in a few lines of code.

In order to use such libraries, and also built-in Python libraries (e.g. os, requests), we need to import them. If a problem occurs while importing them, an import error or a module not found error exception is raised.

For instance, in the following code snippet, we are trying to import the logistic regression class from Scikit-learn.

from sklearn import LogisticRegression

# output
Traceback (most recent call last):
File "<file>", line 3378, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "<ipython-input-22-b74afc1ba453>", line 1, in <module>
from sklearn import LogisticRegression
ImportError: cannot import name 'LogisticRegression' from 'sklearn' (/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/sklearn/__init__.py)

An import error exception is raised because the logistic regression class is available in the linear model module. The correct way of importing it is the following.

from sklearn.linear_model import LogisticRegression

A module not found error exception is raised if the module is not available in the working environment.

import openpyxl

# output
Traceback (most recent call last):
File "<file>", line 3378, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "<ipython-input-23-f5ea1cbb6934>", line 1, in <module>
import openpyxl
File "/Applications/PyCharm CE.app/Contents/plugins/python-ce/helpers/pydev/_pydev_bundle/pydev_import_hook.py", line 21, in do_import
module = self._system_import(name, *args, **kwargs)
ModuleNotFoundError: No module named 'openpyxl'

IndexError

Some data structures have an index that can be used for accessing their items such as lists, tuples, and Pandas DataFrames. We can access a particular item by using sequence subscript.

names = ["John", "Jane", "Max", "Emily"]

# Get the third item
names[2]

# output
"Max"

If the subscript is out of range, an index error exception is raised.

names = ["John", "Jane", "Max", "Emily"]

# Get the sixth item
names[5]

# output
Traceback (most recent call last):
File "<file>", line 3378, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "<ipython-input-30-3033b2837dcd>", line 3, in <module>
names[5]
IndexError: list index out of range

Since the list contains 4 items, an exception is raised when we try to access the sixth item, which does not exist.

Let’s do another example using a Pandas DataFrame.

import pandas as pd
import numpy as np

df = pd.DataFrame(np.random.randint(10, size=(5, 2)), columns=["A", "B"])

df

# output
A B
0 1 6
1 6 3
2 8 8
3 3 5
4 5 6

The variable df is a DataFrame with 5 rows and 2 columns. The following line of code tries to get the value in the third column of the first row.

df.iloc[0, 3]

# output

Traceback (most recent call last):
File "<file>", line 3378, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "<file>", line 1, in <module>
df.iloc[0, 3]
File "<file>", line 960, in __getitem__
return self.obj._get_value(*key, takeable=self._takeable)
File "<file>", line 3612, in _get_value
series = self._ixs(col, axis=1)
File "<file>", line 3439, in _ixs
label = self.columns[i]
File "<file>", line 5039, in __getitem__
return getitem(key)
IndexError: index 3 is out of bounds for axis 0 with size 2

As we see in the last line of the traceback, it’s quite a self-explanatory error message.

NameError

Name error exception is raised when we refer to a variable that is not defined in our code.

Here is an example:

members = ["John", "Jane", "Max", "Emily"]

member[0]

# output
Traceback (most recent call last):
File "<file>", line 3378, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "<ipython-input-35-9fcefb83a26f>", line 3, in <module>
name[5]
NameError: name 'member' is not defined

The name of the variable is members so we get an error when we try to use member instead of members.

ValueError

The value error exception is raised when we try to assign a not-proper value to a variable. Recall our DataFrame with 5 rows and 2 columns.

import pandas as pd
import numpy as np

df = pd.DataFrame(np.random.randint(10, size=(5, 2)), columns=["A", "B"])

df

# output
A B
0 1 6
1 6 3
2 8 8
3 3 5
4 5 6

Let’s say we want to add a new column to this DataFrame.

df["C"] = [1, 2, 3, 4]

# output
Traceback (most recent call last):
File "<file>", line 3378, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "<file>", line 1, in <module>
df["C"] = [1, 2, 3, 4]
File "<file>", line 3655, in __setitem__
self._set_item(key, value)
File "<file>", line 3832, in _set_item
value = self._sanitize_column(value)
File "<file>", line 4535, in _sanitize_column
com.require_length_match(value, self.index)
File "<file>", line 557, in require_length_match
raise ValueError(
ValueError: Length of values (4) does not match length of index (5)

As explained in the error message, the DataFrame has 5 rows so each column has 5 values. When we try to create a new column with a list of 4 items, we get a value error.

Error messages are very helpful in debugging a code or making it execute properly for the first time. Thankfully, Python tracebacks have clear and explanatory error messages.

In this article, we learned what a traceback is, how to read it, and some of the common types of tracebacks.

You can become a Medium member to unlock full access to my writing, plus the rest of Medium. If you already are, don’t forget to subscribe if you’d like to get an email whenever I publish a new article.

Thank you for reading. Please let me know if you have any feedback.


Photo by Anne Nygård on Unsplash

We rarely get a script running without any errors on the first try, which is absolutely normal when writing code. The important and sometimes challenging part is to fix these errors.

The process of fixing the errors and making the script work as expected can take many iterations depending on the experience of the programmer and the information we have about the error. Programming languages give us some hints as to what might be causing the error, which is basically what a Python traceback does.

A traceback in Python can be considered as a report that helps us understand and fix a problem in the code. In this article, we will learn what a traceback in Python is, how to read traceback messages to be able to use them more efficiently, and different error types.

A program in Python stops execution when it encounters an error, which can be in the form of a syntax error or exception. Syntax errors occur when the interpreter detects invalid syntax and they are relatively easier to fix.

An example of a syntax error can be an unmatched parenthesis. On the other hand, an exception is raised when the syntax is correct but the program results in an error.

A traceback is a report that helps us understand the reason for an exception. It contains function calls made in the code along with their line numbers so that we are not clueless about the problem causing the code to fail.

Let’s go over a simple example.

The code snippet below creates a function that adds two numbers and multiplies the sum by the first number. Then, it calls the function with arguments 5 and 4. However, 4 is passed as a string so it is actually not a number.

def add_and_multiply(x, y):
return (x + y) * x

add_and_multiply(5, "4")

When this code is executed, Python raises the following exception:

(image by author)

The last line shows the error type along with a brief explanation. The error in this case is a type error caused by an unsupported operand between integers and strings. The plus operator cannot be used for adding a string to an integer so the code results in an exception.

The lines above the last one tell us where the exception occurred in terms of the function name and the line number. The example we have here is very simple but when working on very long scripts or a program with multiple scripts, information about the function names and line numbers is quite helpful for diagnosing and fixing the issue.

The traceback also shows the module and file names, which is highly helpful when working on scripts that import modules from other files or scripts. How the file and module names are shown change slightly depending on your working environment (e.g. terminal or REPL).

For instance, when I save the code snippet above as “sample_script.py” and try to run it in the terminal, I get the following traceback:

Traceback (most recent call last):
File "/Users/sonery/sample_script.py", line 6, in <module>
add_and_multiply(5, "6")
File "/Users/sonery/sample_script.py", line 2, in add_and_multiply
print((x + y) * x)
TypeError: unsupported operand type(s) for +: 'int' and 'str'

In any case, we get an informative lead in traceback messages.

A substantial amount of time in creating efficient programs and maintaining them in production is spent on debugging errors. Hence, it is of crucial importance to make use of Python tracebacks.

Otherwise, it could take hours to find and fix issues, which might have severe consequences if a program is already deployed into production. ​

The most important part of a traceback message is the error type as it gives us hints about what kind of an error causing the script to stop execution.

Let’s go over some of the commonly encountered error types in the traceback messages.

TypeError

Type error occurs when the data type of an object is not compatible with the defined operation. The example we did in the beginning where an integer and a string are added is an example of this error.

AttributeError

In Python, everything is an object with a type such as integer, string, list, tuple, dictionary, and so on. The types are defined using classes, which also have attributes used for interacting with the objects of a class.

Classes can have data attributes and procedural attributes (i.e. methods):

  • Data attributes: What is needed to create an instance of a class
  • Methods (i.e. procedural attributes): How we interact with instances of a class.

Consider we have an object of type list. We can use the append method for adding a new item to a list. If the object does not have the attribute we are trying to use, an attribute error exception is raised.

Here is an example:

mylist = [1, 2, 3, 4, 5]

mylist.add(10)

# output
Traceback (most recent call last):
File "<file>", line 3378, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "<ipython-input-25-4ad0ec665b52>", line 3, in <module>
mylist.add(10)
AttributeError: 'list' object has no attribute 'add'

Since the list class does not have an attribute called “add”, we get a traceback showing an attribute error.

ImportError and ModuleNotFoundError

Python has a huge selection of third-party libraries (i.e. modules), which makes it possible to complete a lot of tasks in a few lines of code.

In order to use such libraries, and also built-in Python libraries (e.g. os, requests), we need to import them. If a problem occurs while importing them, an import error or a module not found error exception is raised.

For instance, in the following code snippet, we are trying to import the logistic regression class from Scikit-learn.

from sklearn import LogisticRegression

# output
Traceback (most recent call last):
File "<file>", line 3378, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "<ipython-input-22-b74afc1ba453>", line 1, in <module>
from sklearn import LogisticRegression
ImportError: cannot import name 'LogisticRegression' from 'sklearn' (/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/sklearn/__init__.py)

An import error exception is raised because the logistic regression class is available in the linear model module. The correct way of importing it is the following.

from sklearn.linear_model import LogisticRegression

A module not found error exception is raised if the module is not available in the working environment.

import openpyxl

# output
Traceback (most recent call last):
File "<file>", line 3378, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "<ipython-input-23-f5ea1cbb6934>", line 1, in <module>
import openpyxl
File "/Applications/PyCharm CE.app/Contents/plugins/python-ce/helpers/pydev/_pydev_bundle/pydev_import_hook.py", line 21, in do_import
module = self._system_import(name, *args, **kwargs)
ModuleNotFoundError: No module named 'openpyxl'

IndexError

Some data structures have an index that can be used for accessing their items such as lists, tuples, and Pandas DataFrames. We can access a particular item by using sequence subscript.

names = ["John", "Jane", "Max", "Emily"]

# Get the third item
names[2]

# output
"Max"

If the subscript is out of range, an index error exception is raised.

names = ["John", "Jane", "Max", "Emily"]

# Get the sixth item
names[5]

# output
Traceback (most recent call last):
File "<file>", line 3378, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "<ipython-input-30-3033b2837dcd>", line 3, in <module>
names[5]
IndexError: list index out of range

Since the list contains 4 items, an exception is raised when we try to access the sixth item, which does not exist.

Let’s do another example using a Pandas DataFrame.

import pandas as pd
import numpy as np

df = pd.DataFrame(np.random.randint(10, size=(5, 2)), columns=["A", "B"])

df

# output
A B
0 1 6
1 6 3
2 8 8
3 3 5
4 5 6

The variable df is a DataFrame with 5 rows and 2 columns. The following line of code tries to get the value in the third column of the first row.

df.iloc[0, 3]

# output

Traceback (most recent call last):
File "<file>", line 3378, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "<file>", line 1, in <module>
df.iloc[0, 3]
File "<file>", line 960, in __getitem__
return self.obj._get_value(*key, takeable=self._takeable)
File "<file>", line 3612, in _get_value
series = self._ixs(col, axis=1)
File "<file>", line 3439, in _ixs
label = self.columns[i]
File "<file>", line 5039, in __getitem__
return getitem(key)
IndexError: index 3 is out of bounds for axis 0 with size 2

As we see in the last line of the traceback, it’s quite a self-explanatory error message.

NameError

Name error exception is raised when we refer to a variable that is not defined in our code.

Here is an example:

members = ["John", "Jane", "Max", "Emily"]

member[0]

# output
Traceback (most recent call last):
File "<file>", line 3378, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "<ipython-input-35-9fcefb83a26f>", line 3, in <module>
name[5]
NameError: name 'member' is not defined

The name of the variable is members so we get an error when we try to use member instead of members.

ValueError

The value error exception is raised when we try to assign a not-proper value to a variable. Recall our DataFrame with 5 rows and 2 columns.

import pandas as pd
import numpy as np

df = pd.DataFrame(np.random.randint(10, size=(5, 2)), columns=["A", "B"])

df

# output
A B
0 1 6
1 6 3
2 8 8
3 3 5
4 5 6

Let’s say we want to add a new column to this DataFrame.

df["C"] = [1, 2, 3, 4]

# output
Traceback (most recent call last):
File "<file>", line 3378, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "<file>", line 1, in <module>
df["C"] = [1, 2, 3, 4]
File "<file>", line 3655, in __setitem__
self._set_item(key, value)
File "<file>", line 3832, in _set_item
value = self._sanitize_column(value)
File "<file>", line 4535, in _sanitize_column
com.require_length_match(value, self.index)
File "<file>", line 557, in require_length_match
raise ValueError(
ValueError: Length of values (4) does not match length of index (5)

As explained in the error message, the DataFrame has 5 rows so each column has 5 values. When we try to create a new column with a list of 4 items, we get a value error.

Error messages are very helpful in debugging a code or making it execute properly for the first time. Thankfully, Python tracebacks have clear and explanatory error messages.

In this article, we learned what a traceback is, how to read it, and some of the common types of tracebacks.

You can become a Medium member to unlock full access to my writing, plus the rest of Medium. If you already are, don’t forget to subscribe if you’d like to get an email whenever I publish a new article.

Thank you for reading. Please let me know if you have any feedback.

FOLLOW US ON GOOGLE NEWS

Read original article here

Denial of responsibility! Techno Blender is an automatic aggregator of the all world’s media. In each content, the hyperlink to the primary source is specified. All trademarks belong to their rightful owners, all materials to their authors. If you are the owner of the content and do not want us to publish your materials, please contact us by email – [email protected]. The content will be deleted within 24 hours.

Leave a comment