Python 3.11 New Features
Python 3.11.1 is the newest major release of the Python programming language, and it contains many new features and optimizations. See source repository from talkpython.
Installation on Arch Linux
python3 -V
Python 3.10.8
wget https://www.python.org/ftp/python/3.11.1/Python-3.11.1.tar.xz
tar -xvf Python-3.11.1.tar.xz
rn Python-3.11.1.tar.xz
cd Python-3.11.1
sudo ./configure --enable-optimizations
sudo make altinstall
python -V
Python 3.10.8
python3 -V
Python 3.10.8
python3.11 -V
Python 3.11.1
👍
Improved Error Messages
Example 1
Showing the exact location where an error occurred - instead of just the line:
def func1(data, b, c, d, e, f):
area = data.get(b).get(c).get(d).get(e)
units = data.get(b).get(c).get(d).get(f).strip().lower()
return area, string.capwords(units)
def main():
data = {
"region": {
"country": {
"size": {
"area": 1_000_000,
"units": "MILES",
}
}
}
}
b = "region"
c = "country"
d = "size"
e = "area"
f = "units"
# extract area and units - this works
print(func1(data, b, c, d, e, f))
# breaking the function by calling a non-existing key
f = "anonkey"
print(func1(data, b, c, d, e, f))
Python 3.10
(1000000, 'Miles')
Traceback (most recent call last):
File "01_error_messages.py", line 67, in <module>
main()
File "01_error_messages.py", line 44, in main
print(func1(data, b, c, d, e, f))
File "01_error_messages.py", line 9, in func1
units = data.get(b).get(c).get(d).get(f).strip().lower()
AttributeError: 'NoneType' object has no attribute 'strip'
Python 3.11
Trying to strip f
failed because it does not exist:
(1000000, 'Miles')
Traceback (most recent call last):
File "01_error_messages.py", line 67, in <module>
main()
^^^^^^
File "01_error_messages.py", line 44, in main
print(func1(data, b, c, d, e, f))
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "01_error_messages.py", line 9, in func1
units = data.get(b).get(c).get(d).get(f).strip().lower()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'strip'
Example 2
Thing = namedtuple("Thing", "name, weight, speed")
def func2(a, b, c, d):
return a + b + c + d
def main():
t1 = Thing("Bob", 70, 24)
t2 = Thing("Sarah", 65, 32)
t3 = Thing("Jake", 72, 20)
print(func2(1, 2, 3, 4))
print(func2(1, 2, "3", 4))
Python 3.10
10
Traceback (most recent call last):
File "01_error_messages.py", line 56, in <module>
main()
File "01_error_messages.py", line 47, in main
print(func2(1, 2, "3", 4))
File "01_error_messages.py", line 15, in func2
return a + b + c + d
TypeError: unsupported operand type(s) for +: 'int' and 'str'
Python 3.11
Adding b
to c
does not work because one of them is a string:
10
Traceback (most recent call last):
File "01_error_messages.py", line 56, in <module>
main()
^^^^^^
File "01_error_messages.py", line 47, in main
print(func2(1, 2, "3", 4))
^^^^^^^^^^^^^^^^^^^
File "01_error_messages.py", line 15, in func2
return a + b + c + d
~~~~~~^~~
TypeError: unsupported operand type(s) for +: 'int' and 'str'
Customized Exception Notes
Exception notes with add_note, which enables you to add customized messages.
Example 1
Add additional information about what might have gone wrong to the error message:
def divide_by_zero(x):
try:
1/x
except Exception as myError:
myError.add_note(f'The value of x is ZERO. Raised at {datetime.now()}')
def main():
x = 0
divide_by_zero(x)
Python 3.10
This code is incompatible with Python 3.10 => AttributeError: 'ZeroDivisionError' object has no attribute 'add_note'
Python 3.11
python3.11 02_custom_exception.py
Traceback (most recent call last):
File "02_custom_exception.py", line 63, in <module>
main()
File "02_custom_exception.py", line 46, in main
divide_by_x(x)
File "02_custom_exception.py", line 7, in divide_by_x
1/x
~^~
ZeroDivisionError: division by zero
The value of x is ZERO. Raised at 2023-01-16 13:37:26.197005
Example 2
Write some test that check if the input is correct and append them to the regular error message:
class DbException(Exception):
pass
class DbConnectionException(DbException):
pass
def connect_to_db(conn_str, server: Optional[str] = None, port: Optional[int] = None):
if ("server=" in conn_str and server) or ("port=" in conn_str and port):
raise DbConnectionException("Connection string is malformed")
conn_str += f"&server={server}&port={port}"
print(f"Connecting to DB with {conn_str}")
def setup_app():
# conn_str = "mongo://user=mk&password=a&database=talkpython"
conn_str = "mongo://user=mk&password=a&database=talkpython&port=1000"
server = "localhost"
port = 27017
try:
connect_to_db(conn_str, server, port)
except DbConnectionException as dbe:
dbe.add_note('You cannot specify server or port in both the conn str and explicitly')
dbe.add_note('Amend the conn string and try again.')
raise
Here the server address and port is added twice creating a connection error.
Python 3.10
This code is incompatible with Python 3.10 => AttributeError: 'ZeroDivisionError' object has no attribute 'add_note'
Python 3.11
Our exception is triggered and we receive both the connection error that the connection string is malformed as well as the note that our test was triggered:
python3.11 02_custom_exception.py
Error starting app:
DbConnectionException: Connection string is malformed
There are 2 notes
Note: You cannot specify server or port in both the conn str and explicitly
Note: Amend the conn string and try again