Skip to content

Commit 851967e

Browse files
committed
completing the exception handling chapter
1 parent a21d4ed commit 851967e

File tree

8 files changed

+139
-5
lines changed

8 files changed

+139
-5
lines changed

book.tex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
\pdfminorversion=7%
12
\documentclass[a4paper,oneside,10pt]{memoir}%
23
%
34
\setsecnumdepth{subsubsection}% number down to sub-sub-sections

styles/colors.sty

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
\colorlet{listing-emph-1}{blue}%
3131
\colorlet{listing-emph-2}{listing-keyword-1}%
3232
\colorlet{listing-emph-3}{Mahogany!90!black}%
33-
\colorlet{listing-emph-4}{yellow!30!red!30!black}%
33+
\colorlet{listing-emph-4}{red!30!black}%
3434
\colorlet{listing-emph-5}{violet!80!black}%
3535
\colorlet{listing-emph-6}{violet}%
3636
\colorlet{listing-emph-7}{listing-keyword-1}%

styles/listing.sty

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ otherkeywords={\%,\},\{,\&,\|},%
7676
emph={and,break,class,continue,def,yield,del,elif,else,except,exec,finally,for,from,global,if,import,in,lambda,not,or,pass,print,raise,return,try,while,assert,with},%
7777
emph={[2]True,False,None},%
7878
emph={[3]object,type,isinstance,deepcopy,zip,enumerate,reversed,list,set,len,dict,tuple,xrange,append,execfile,real,imag,reduce,str,repr,range},%
79-
emph={[4]AssertionError,Exception,IndexError,NameError,OverflowError,SyntaxError,TypeError,ValueError,ZeroDivisionError},%
79+
emph={[4]ArithmeticError,AssertionError,AttributeError,BaseException,BlockingIOError,BrokenPipeError,BufferError,ChildProcessError,ConnectionAbortedError,ConnectionError,ConnectionRefusedError,ConnectionResetError,EOFError,Exception,FileExistsError,FileNotFoundError,FloatingPointError,GeneratorExit,ImportError,IndentationError,IndexError,IsADirectoryError,KeyboardInterrupt,KeyError,LookupError,MemoryError,ModuleNotFoundError,NameError,NotADirectoryError,NotImplementedError,OSError,OverflowError,PermissionError,ProcessLookupError,PythonFinalizationError,RecursionError,ReferenceError,RuntimeError,StopAsyncIteration,StopIteration,SyntaxError,SystemError,SystemExit,TabError,TimeoutError,TypeError,UnboundLocalError,UnicodeDecodeError,UnicodeEncodeError,UnicodeError,UnicodeTranslateError,ValueError,ZeroDivisionError,},%
8080
emph={[5]__init__,__add__,__mul__,__div__,__sub__,__call__,__getitem__,__setitem__,__eq__,__ne__,__new__,__nonzero__,__rmul__,__radd__,__repr__,__str__,__get__,__truediv__,__pow__,__name__,__future__,__all__},%
8181
morestring=[s]{"""}{"""},%
8282
}%

styles/styles.sty

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,5 @@
4040
\crefname{page}{page}{pages}%
4141
\Crefname{page}{Page}{Pages}%
4242
%
43+
\RequirePackage{dirtree}%
44+
%

text/main/basics/gettingStarted/examples/examples.tex

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,5 @@
7777
After making sure that you indeed downloaded the examples for this book (and if you deem this code trustworthy), you can click \menu{Trust Project}, as \cref{fig:clone04trustProject}.
7878
Finally, as \cref{fig:clone05finished} shows, you can now see and play with and run all the examples in \pycharm.%
7979
%
80-
\FloatBarrier%
8180
\endhsection%
8281
%

text/main/basics/gettingStarted/summary/summary.tex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
In this introductory section, we have performed the very first steps into the domain of \python\ programming.
44
We have now a computer where both \python\ and the \pycharm\ \pgls{IDE} are installed.
55
We can create program files and we can execute them in different ways.
6+
We also obtained the set of example programs that will later be used in this book.
67
We are now ready to learn how to program.%
78
%
89
\endhsection%

text/main/basics/simpleDataTypesAndOperations/introduction/introduction.tex

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,5 +46,9 @@
4646
%
4747
\end{itemize}%
4848
%
49+
Here, we will not yet really write \python\ programs.
50+
Instead, we will use the \python\ interpreter console more like a fancy calculator.
51+
This will allow us to explore the basic functionality regarding the above-mentioned datatypes efficiently and freely.%
52+
%
4953
\endhsection%
5054
%

text/main/controlFlow/exceptions/exceptions.tex

Lines changed: 129 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -587,7 +587,7 @@
587587
This very large integer values will eventually be converted to a \pythonil{float} inside our function.
588588
This will fail, because it is too large, as we just discussed back in \cref{sec:tryFinally}.
589589
This failure results in an \pythonilIdx{OverflowError}.
590-
\pythonilsIdx{OverflowError} are a special case of \pythonilIdx{ArithmeticError}.
590+
\pythonilsIdx{OverflowError} are a special case of \pythonilIdx{ArithmeticError} (see later in \cref{fig:pythonExceptions}).
591591
So indeed, this does fulfill our testing requirement:
592592
If an \pythonilsIdx{OverflowError} is also a \pythonilIdx{ArithmeticError}, so the right type of \pythonilIdx{Exception} was raised.
593593
However, its error message will not fit to our \pythonil{match} argument.
@@ -624,8 +624,135 @@
624624
\endhsection%
625625
%
626626
\hsection{Built-in Exceptions}%
627-
\cite{PSF2024BIE}
627+
%
628+
\begin{figure}%
629+
\centering%
630+
\renewcommand*\DTstylecomment{\relax}%
631+
\renewcommand*\DTstyle{\small}%
632+
%
633+
\dirtree{%
634+
.1 \pythonilIdx{BaseException}\DTcomment{the base \pythonilIdx{class} for all exceptions}.
635+
.2 \pythonilIdx{Exception}\DTcomment{situations where reasonable error handling should be possible}.
636+
.3 \pythonilIdx{ArithmeticError}\DTcomment{an arithmetic operation failed}.
637+
.4 \pythonilIdx{FloatingPointError}\DTcomment{not used by \python, but, e.g., \pgls{numpy} on invalid floating point operations}.
638+
.4 \pythonilIdx{OverflowError}\DTcomment{the result of an arithmetic operations is too large, see, e.g., \cref{sec:float:special}}.
639+
.4 \pythonilIdx{ZeroDivisionError}\DTcomment{a division by zero occurred, see, e.g., \cref{sec:unitTesting}}.
640+
.3 \pythonilIdx{AssertionError}\DTcomment{if an \pythonilIdx{assert} failed}.
641+
.3 \pythonilIdx{BufferError}\DTcomment{a buffer-related operation could not be performed}.
642+
.3 \pythonilIdx{EOFError}\DTcomment{the end of \pgls{stdin} was reached by \pythonilIdx{input} without reading data}.
643+
.3 \pythonilIdx{AttributeError}\DTcomment{when an attribute reference or assignment failed}.
644+
.3 \pythonilIdx{ImportError}\DTcomment{when an \pythonilIdx{import} statement fails}.
645+
.4 \pythonilIdx{ModuleNotFoundError}\DTcomment{a module cannot be loaded}.
646+
.3 \pythonilIdx{LookupError}\DTcomment{a key or index used on a dictionary or sequence was invalid}.
647+
.4 \pythonilIdx{IndexError}\DTcomment{a sequence index is out of range, see, e.g., \cref{sec:strBasicOperations}}.
648+
.4 \pythonilIdx{KeyError}\DTcomment{a dictionary key is not found, see, e.g., \cref{sec:dictionaries}}.
649+
.3 \pythonilIdx{MemoryError}\DTcomment{when we are out of memory}.
650+
.3 \pythonilIdx{NameError}\DTcomment{e.g., when reading an unassigned variable, see, e.g., \cref{lst:exceptions:try_multi_except}}.
651+
.4 \pythonilIdx{UnboundLocalError}\DTcomment{reference to a local method or function to which no value is bound}.
652+
.3 \pythonilIdx{OSError}\DTcomment{an operating system function failed}.
653+
.4 \pythonilIdx{BlockingIOError}\DTcomment{a blocking operation is applied to an object set for non-blocking operations}.
654+
.4 \pythonilIdx{ChildProcessError}\DTcomment{an operation on a child process failed}.
655+
.4 \pythonilIdx{ConnectionError}\DTcomment{a connection- or pipe-related error}.
656+
.5 \pythonilIdx{BrokenPipeError}\DTcomment{when trying to write into a pipe whose other end has been closed}.
657+
.5 \pythonilIdx{ConnectionAbortedError}\DTcomment{connection attempt aborted by peer}.
658+
.5 \pythonilIdx{ConnectionRefusedError}\DTcomment{connection refused by peer}.
659+
.5 \pythonilIdx{ConnectionResetError}\DTcomment{connection reset by peer}.
660+
.4 \pythonilIdx{FileExistsError}\DTcomment{trying to create a file that already exists}.
661+
.4 \pythonilIdx{FileNotFoundError}\DTcomment{trying to access a file or directory that does not exist}.
662+
.4 \pythonilIdx{IsADirectoryError}\DTcomment{trying to do a file operation with a directory}.
663+
.4 \pythonilIdx{NotADirectoryError}\DTcomment{trying to apply a directory operation to a file}.
664+
.4 \pythonilIdx{PermissionError}\DTcomment{trying to perform an operation without the necessary access rights}.
665+
.4 \pythonilIdx{ProcessLookupError}\DTcomment{trying to access a process that does not exist}.
666+
.4 \pythonilIdx{TimeoutError}\DTcomment{an operation timed out}.
667+
.3 \pythonilIdx{ReferenceError}\DTcomment{a weakly-referenced object is accessed after being garbage collected}.
668+
.3 \pythonilIdx{RuntimeError}\DTcomment{an error that does not fall into the other categories}.
669+
.4 \pythonilIdx{NotImplementedError}\DTcomment{a method has not yet been implement, but will be later}.
670+
.4 \pythonilIdx{PythonFinalizationError}\DTcomment{an operation is blocked during interpreter shutdown}.
671+
.4 \pythonilIdx{RecursionError}\DTcomment{the maximum recursion depth of functions is reached}.
672+
.3 \pythonilIdx{StopAsyncIteration}\DTcomment{signals the end of an asynchronous iteration; not an error}.
673+
.3 \pythonilIdx{StopIteration}\DTcomment{signals the end of an iteration; not an error}.
674+
.3 \pythonilIdx{SyntaxError}\DTcomment{an malformed \python\ file}.
675+
.4 \pythonilIdx{IndentationError}\DTcomment{incorrectly indented code}.
676+
.5 \pythonilIdx{TabError}\DTcomment{inconsistent use of tabs and spaces}.
677+
.3 \pythonilIdx{SystemError}\DTcomment{an internal error of the interpreter}.
678+
.3 \pythonilIdx{TypeError}\DTcomment{some parameter was of a wrong type or \pythonilIdx{None}, see, e.g., \cref{sec:tuples}}.
679+
.3 \pythonilIdx{ValueError}\DTcomment{a parameter has the right type but an inappropriate value, see, e.g., \cref{lst:exceptions:try_except_str_index}}.
680+
.4 \pythonilIdx{UnicodeError}\DTcomment{an error when dealing with \pgls{unicode} text}.
681+
.5 \pythonilIdx{UnicodeDecodeError}\DTcomment{an error occurred when decoding \pgls{unicode} text}.
682+
.5 \pythonilIdx{UnicodeEncodeError}\DTcomment{an error occurred when encoding \pgls{unicode} text}.
683+
.5 \pythonilIdx{UnicodeTranslateError}\DTcomment{an error occurred when translating \pgls{unicode} text}.
684+
.2 \pythonilIdx{GeneratorExit}\DTcomment{when a \pythonilIdx{Generate} or coroutine terminate; not an error}.
685+
.2 \pythonilIdx{KeyboardInterrupt}\DTcomment{when the user hits \keys{\ctrl+C}}.
686+
.2 \pythonilIdx{SystemExit}\DTcomment{raised by \pythonilIdx{exit}; not an error}.
687+
}%
688+
%
689+
\caption{An overview of the hierarchy of \pythonilsIdx{Exception} in \python~\cite{PSF2024BIE}.}%
690+
\label{fig:pythonExceptions}%
691+
\end{figure}%
692+
%
693+
A wide variety of things may go wrong during the execution of a computer program.
694+
We have already explored a lot of different potential errors, ranging from using an invalid index when accessing a list to dividing a number by zero.
695+
In \python, \pythonilsIdx{Exception} are raised\pythonIdx{raise} in such a situation.
696+
An \pythonilIdx{Exception} disrupts the normal control flow and propagates upwards until a corresponding \pythonilIdx{except} clause is reached.
697+
Obviously, we cannot just treat every possible error condition in the same way.
698+
699+
Running out of memory is a completely different situation than trying to read from a non-existing file.
700+
Therefore, different types of \pythonilsIdx{Exception} are raised:
701+
The former problem causes a \pythonilIdx{MemoryError} while the later raises an \pythonilIdx{FileNotFoundError}.
702+
The hierarchy of the different problem types is illustrated in \cref{fig:pythonExceptions}~\cite{PSF2024BIE}.
703+
There, you can also see why an \pythonilIdx{except} block catching \pythonilsIdx{ArithmeticError} would also catch an \pythonilsIdx{OverflowError}, because the latter is a special case of the former.
704+
705+
Depending on the operations that your code tries to perform, you would wrap it into \pythonilIdx{except} blocks for the errors from this list that you could reasonably expect to be able to recover from.
706+
Of course, the documentation of the \python\ functions that you use will tell you which \pythonilsIdx{Exception} it could raise.
707+
And so should the \pglspl{docstring} of your own code as well as library functions you rely on.%
628708
\endhsection%
629709
%
710+
\hsection{Summary}%
711+
In this chapter, we have dealt with a very important subject in programming:
712+
How we handle errors.
713+
Errors can arise from a wide variety of reasons.
714+
715+
They can be caused by invalid or corrupted data being passed to our program.
716+
In this case, our program should fail and print an error message to the user.
717+
718+
They can be caused by a programming mistake:
719+
Maybe another programmer uses a function that we have written, but passes a parameter of a wrong type to it.
720+
For example, maybe they pass in a string where we expect a number.
721+
Or maybe they pass a negative number when we expect a positive one.
722+
In this case, our program should fail and print an error message to the user.
723+
724+
Failing by raising an \pythonilIdx{Exception} is a good thing.
725+
It clearly indicates that something is wrong.
726+
It gives the user or our fellow programmers a chance to become aware of an error and to take action to fix it.
727+
Other approaches, like \pgls{GIGO} or overly sanitizing corrupted input instead allow errors to propagate unnoticed.
728+
729+
Maybe some of the readers of this book are graduate or undergraduate students who use \python\ to implement code for experiments.
730+
Imagine how annoying it is to run an experiment and to find out one week later that all the data produced is garbage.
731+
You then not only feel sad about the waste of time, but now need to waste even more time:
732+
Where was the error?
733+
Maybe it would take another week to painstakingly debug your code step-by-step to find out that some function was used incorrectly due to a typo.
734+
How much better would it have been if the experiment had crashed right at its start, printing an \pythonilIdx{Exception} and \pgls{stackTrace} to the \pgls{stdout} showing exactly where things went wrong?
735+
It would have saved you two weeks and lots of grief.
736+
737+
Of course, there are also situations where it is possible to gracefully recover from an error.
738+
For example, maybe our program is trying to delete a file that already has been deleted.
739+
The operation would fail, but that does not do any harm.
740+
For these scenarios, the \pythonilIdx{except} blocks exist.
741+
They allow us to catch errors which we can reasonably expect and that are no show stoppers.
742+
743+
Finally, there is the \pythonilIdx{finally} block.
744+
This block allows us to properly complete an operation regardless whether an error happened or not.
745+
If we send data over an internet connection, we want to close this connection properly after we are done.
746+
We also want to close it if something goes wrong.
747+
If we write data to a file, then we want to close the file once we are done.
748+
We still want to close it properly if an error occurs, because then we can at least preserve the data that was already successfully written.
749+
750+
Error handling in \python\ therefore allows us to develop software that is both robust and that clearly indicates if something goes wrong.
751+
Of course, for software to be called \emph{robust}, it has to be tested.
752+
Luckily, \pytest\ offers us also unit testing capabilities that check whether \pythonilsIdx{Exceptions} are raised where expected.
753+
This completes our discussion of the error-related control flow.%
754+
\endhsection%
755+
%
756+
\FloatBarrier%
630757
\endhsection%
631758
%

0 commit comments

Comments
 (0)