15.2. Exception Raise

  • Used when error occurs

  • You can catch exception and handles erroneous situation

  • If file does not exists

  • If no permissions to read file

  • If function argument is invalid type (ie. int('one'))

  • If value is incorrect (ie. negative Kelvin temperature)

  • If network or database connection could not be established

15.2.1. Raising Exceptions

  • Exceptions can have message

  • You choose which exception best represent error

Raise Exception without message:

>>> raise RuntimeError
Traceback (most recent call last):
RuntimeError

Exception with additional message:

>>> raise RuntimeError('Some message')
Traceback (most recent call last):
RuntimeError: Some message

15.2.2. Example

We want to check if Kelvin temperature given by user is not negative. Note that Kelvin temperatures below zero doesn't exist, hence it's an absolute scale. In order to do so, we need to ask user to input value. Let's assume user input -1.

>>> temperature = -1  # User input this value

Now we need to check if the temperature is not negative. If temperature is 0 or above we can proceed with program execution. However if the temperature is below zero... Then we should warn user about problem and exit the program. This is why we have exceptions. We can break execution of a program in erroneous situations.

>>> if temperature > 0.0:
...     print('Temperature is valid')
... else:
...     raise ValueError('Kelvin cannot be negative')
Traceback (most recent call last):
ValueError: Kelvin cannot be negative

Good software communicates well with programmer. Exceptions are common language to talk about problems and not-nominal (abnormal) situations in your code.

>>> def check(temperature):
...     if type(temperature) not in {float, int}:
...         raise TypeError('Temperature must be int or float')
...     if temperature < 0:
...         raise ValueError('Kelvin temperature cannot be negative')
...     return temperature

15.2.3. Use Case - 1

>>> def apollo13():
...     raise RuntimeError('Oxygen tank explosion')
>>>
>>>
>>> apollo13()
Traceback (most recent call last):
RuntimeError: Oxygen tank explosion
>>> def apollo18():
...     raise NotImplementedError('Mission dropped due to budget cuts')
>>>
>>>
>>> apollo18()
Traceback (most recent call last):
NotImplementedError: Mission dropped due to budget cuts

15.2.4. Hierarchy

  • All exceptions derives from BaseException

  • There are three most important exceptions: KeyboardInterrupt, SystemExit, GeneratorExit

  • All others exceptions derive from Exception

  • There are also warnings, which derives from Warning

../../_images/exception-hierarchy.png

Figure 15.1. A small portion of the class hierarchy of Python's standard exceptions. This diagram omits 1 other standard class derived directly from BaseException and 56 other classes derived directly or indirectly from Exception. Source [1]

BaseException
 +-- SystemExit
 +-- KeyboardInterrupt
 +-- GeneratorExit
 +-- Exception
      +-- StopIteration
      +-- StopAsyncIteration
      +-- ArithmeticError
      |    +-- FloatingPointError
      |    +-- OverflowError
      |    +-- ZeroDivisionError
      +-- AssertionError
      +-- AttributeError
      +-- BufferError
      +-- EOFError
      +-- ImportError
      +-- LookupError
      |    +-- IndexError
      |    +-- KeyError
      +-- MemoryError
      +-- NameError
      |    +-- UnboundLocalError
      +-- OSError
      |    +-- BlockingIOError
      |    +-- ChildProcessError
      |    +-- ConnectionError
      |    |    +-- BrokenPipeError
      |    |    +-- ConnectionAbortedError
      |    |    +-- ConnectionRefusedError
      |    |    +-- ConnectionResetError
      |    +-- FileExistsError
      |    +-- FileNotFoundError
      |    +-- InterruptedError
      |    +-- IsADirectoryError
      |    +-- NotADirectoryError
      |    +-- PermissionError
      |    +-- ProcessLookupError
      |    +-- TimeoutError
      +-- ReferenceError
      +-- RuntimeError
      |    +-- NotImplementedError
      |    +-- RecursionError
      +-- SyntaxError
      |    +-- IndentationError
      |         +-- TabError
      +-- SystemError
      +-- TypeError
      +-- ValueError
      |    +-- UnicodeError
      |         +-- UnicodeDecodeError
      |         +-- UnicodeEncodeError
      |         +-- UnicodeTranslateError
      +-- Warning
           +-- DeprecationWarning
           +-- PendingDeprecationWarning
           +-- RuntimeWarning
           +-- SyntaxWarning
           +-- UserWarning
           +-- FutureWarning
           +-- ImportWarning
           +-- UnicodeWarning
           +-- BytesWarning
           +-- ResourceWarning

15.2.5. References

15.2.6. Assignments

# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author

# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`

# %% About
# - Name: Exception Raise One
# - Difficulty: easy
# - Lines: 2
# - Minutes: 3

# %% English
# 1. Validate value passed to a `is_positive` function:
#    - If `value` is less or equal to zero, raise `ValueError`
# 2. Write solution inside `is_positive` function
# 3. Run doctests - all must succeed

# %% Polish
# 1. Sprawdź poprawność wartości przekazanej do funckji `is_positive`:
#    - Jeżeli `value` jest mniejsze lub równa zero, podnieś wyjątek `ValueError`
# 2. Rozwiązanie zapisz wewnątrz funkcji `is_positive`
# 3. Uruchom doctesty - wszystkie muszą się powieść

# %% Hints
# - `if`
# - `raise`

# %% Tests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 9), \
'Python 3.9+ required'

>>> is_positive(1)

>>> is_positive(0)
Traceback (most recent call last):
ValueError

>>> is_positive(-1)
Traceback (most recent call last):
ValueError
"""

# Validate value passed to a `is_positive` function:
# If `value` is less or equal to zero, raise `ValueError`
# Write solution inside `is_positive` function
# type: Callable[[int], None]
def is_positive(value):
    ...


# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author

# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`

# %% About
# - Name: Exception Raise Many
# - Difficulty: easy
# - Lines: 6
# - Minutes: 3

# %% English
# 1. Validate value passed to a `result` function
# 2. If `value` is:
#    - other type than `int` or `float` raise `TypeError`
#    - is not between 0 and 130, raise `ValueError`
#    - less than 18, raise `PermissionError`
# 3. Write solution inside `result` function
# 4. Run doctests - all must succeed

# %% Polish
# 1. Sprawdź poprawność wartości przekazanej do funckji `result`
# 2. Jeżeli `age` jest:
#    - innego typu niż `int` lub `float`, podnieś wyjątek `TypeError`
#    - nie jest pomiędzy od 0 do 130, podnieś wyjątek `ValueError`
#    - mniejsza niż 18, podnieś wyjątek `PermissionError`
# 3. Rozwiązanie zapisz wewnątrz funkcji `result`
# 4. Uruchom doctesty - wszystkie muszą się powieść

# %% Hints
# - `not`
# - `raise`
# - `if`
# - `type()`

# %% Tests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 9), \
'Python 3.9+ required'

>>> result(18)

>>> result(17.9999)
Traceback (most recent call last):
PermissionError

>>> result(-1)
Traceback (most recent call last):
ValueError

>>> result('one')
Traceback (most recent call last):
TypeError

>>> result(True)
Traceback (most recent call last):
TypeError
"""

# Validate value passed to a `result` function
# If `value` is:
# - other type than `int` or `float` raise `TypeError`
# - is not between 0 and 130, raise `ValueError`
# - less than 18, raise `PermissionError`
# Write solution inside `result` function
# type: Callable[[int|float], None]
def result(age):
    ...


# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author

# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`

# %% About
# - Name: Exception Raise PermissionError
# - Difficulty: easy
# - Lines: 4
# - Minutes: 5

# %% English
# 1. Check username and password passed to a `login` function
# 2. If `username` is 'mwatney' and `password` is 'Ares3'
#    then print 'User login'
# 3. If any value is other than mentioned, raise an exception
#    PermissionError with message 'Invalid username and/or password'
# 4. Run doctests - all must succeed

# %% Polish
# 1. Sprawdź username i password przekazane do funckji `login`
# 2. Jeżeli username jest 'mwatney' i hasło jest 'Ares3'
#    to wyświetl na ekranie napis 'User login'
# 3. Jeżeli którakolwiek wartość jest inna, to podnieś wyjątek
#    PermissionError z komunikatem 'Invalid username and/or password'
# 4. Uruchom doctesty - wszystkie muszą się powieść

# %% Hints
# - `not in`
# - `raise`
# - `if`

# %% Tests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 9), \
'Python 3.9+ required'

>>> login('mwatney', 'Ares3')
User login

>>> login('invalid', 'Ares3')
Traceback (most recent call last):
PermissionError: Invalid username and/or password

>>> login('mwatney', 'invalid')
Traceback (most recent call last):
PermissionError: Invalid username and/or password

>>> login('invalid', 'invalid')
Traceback (most recent call last):
PermissionError: Invalid username and/or password
"""

# Username must be 'mwatney'
# Password must be 'Ares3'
# If user and password are correct print 'User login'
# Else: raise an exception PermissionError with message 'Invalid username and/or password'
# type: Callable[[str,str], Exception|None]
def login(username, password):
    ...