Warning
Most of the documentation was written prior to version 0.5 and needs to be updated. This work has now started for version 0.7 and we aim to have it completed before version 0.8 is available.
Some thoughts on the design of friendly¶
The following are thoughts on the design of this project. More information about various design choices are scattered throughout this documentation. If you can think of better design choices, please feel free to file an issue.
Original purpose¶
friendly’s primary purpose is to make it easier for beginners and/or for people that have limited knowledge of English to understand what caused a program to generate a traceback.
A secondary goal is to help them learn how to decipher a normal Python traceback and use the information provided by Python to understand what went wrong and how to fix it.
Revised purpose¶
As friendly was developed, we found that going beyond providing an explanation for the traceback printed by Python was potentially very useful. This is something that is currently done by Thonny which, in some cases, even attempts to identify more than one possible cause giving rise to an exception, as well as ordering them in order of likelihood, based on its own analysis of the code.
As a concrete example, in the image below, Thonny shows the normal Python traceback [1], and offers some additional explanations [2], parts of which can be hidden or revealed by clicking on a button.
For now, friendly usually tries to identify the most likely cause of the exception, but makes some additional suggestions in a few relatively rare cases.
Gradual reveal¶
Initially, it was thought that the information provided by friendly
should be shown all at once. As we accumulated more and more cases,
we realised that this could yield a huge amount of material which could
be rather daunting for beginners. Eventually, this lead to the
approach of using a REPL whenever possible so that the user could get
some small amount of information at a time by entering what()
,
why()
or where()
.
As part of the gradual reveal, the traceback shown to the user shows an added “hint” which attempts to summarize in a single sentence a possible cause or remedy to the exception that was raised. This has been inspired in parts by the DidYouMean-Python (aka BetterErrorMessages) project.
Summary of design choices¶
Scattered throughout this documentation, we added notes about choices that were made in designing friendly and friendly-traceback. These are are listed below.
Design Choice: automatic installation for Jupyter
Anyone using friendly in a Jupyter environment does so because
they want the traceback information to be processed by friendly.
For this reason, friendly is automatically installed when
friendly.jupyter
is imported, instead of requiring users
to call install()
after the import
statement.
(The original entry is located in C:\Users\Andre\github\friendly-docs\source\jupyter.rst, line 64.)
UI Design Choice: buttons instead of function calls for Jupyter
friendly aims to be as easy to use as possible for beginners. Having them clicking on buttons to reveal some additional information when needed is more user-friendly than requiring them to type in and execute some function calls.
(The original entry is located in C:\Users\Andre\github\friendly-docs\source\jupyter.rst, line 74.)
Design Choice: only message shown by default for Jupyter
Rather than showing the friendly traceback by default,
only the exception message is shown in addition to the More ...
button.
(The original entry is located in C:\Users\Andre\github\friendly-docs\source\jupyter.rst, line 85.)
Design Choice: Jupyter font family with Rich
Instead of using the Jupyter default, Rich specifies a set of possible fonts for its output. As a result, the apparent size of the fonts, at least on Windows, appears to be larger when using Rich than without. To avoid this, I override the default from Rich to give a more consistent look and feel.
(The original entry is located in C:\Users\Andre\github\friendly-docs\source\jupyter.rst, line 217.)
UI Design Choice: Red means exception or error
For both themes, I have chosen to use the colour red only for
exception names, such as SyntaxError
, for traceback headings,
and for headings showing where an exception occurred.
(The original entry is located in C:\Users\Andre\github\friendly-docs\source\themes.rst, line 26.)
Note
The sections shown below will likely be moved elsewhere
About Warnings¶
In addition to generating exceptions, Python can provide some Warnings to users. For now, these are simply silenced but we would like to consider including them in the information provided by friendly.
Location of the exception¶
While a Python traceback includes the information from all the frames that were involved, friendly focus on the first and last frame, as these are more likely to contain the relevant information to the user.
Variable information¶
friendly include the value of all known variables found
on the lines of code shown; earlier versions, such
as that shown in the example below, included only variable information
from a single line of code. In the example below (IndexError
), this
information [1] together with the reminder [2] and the code from
the offending line [3] give enough information to properly diagnose the error.
In some cases, the value of some variables could, in principle,
yield an enormous amount of text.
To avoid this situation, we truncate any value that exceeds a predetermined
length. However, when we do so, if the variable has a __len__
attribute,
we show its value as it can sometimes be helpful in identifying the problem.
SyntaxError: invalid syntax¶
For SyntaxError
, Python often offers very little useful information
beyond where it finally identified that a SyntaxError
occurred.
Sometimes, the offending code actually occurred well before: for example,
an open bracket might have been inserted many lines prior to where
the absence of the corresponding closing bracket was noted to cause an error.
For SyntaxError
, friendly does a fairly simple analysis
of the code and tries to identify a single cause which produced the
error.
Localization¶
It is possible to translate almost all the text provided by friendly.
When using Python, it is customary to determine which language should
be used to provide translations by a call to
locale.getdefaultlocale()
. In an earlier version, we did this
but have decided to use English as the default and let the user
(which could be another program that imports friendly)
decide what language should be used.
The information provided by locale.getdefaultlocale()
includes
not only a language code, but information about a specific region as well.
For example, on my computer, this is fr_CA
. As far as I can tell,
gettext does not have a graceful fallback from the specific (fr_CA
)
to the generic (fr
); it does have the option of having a fallback
to the version hard-coded in a program.
What we have done is including the possibility of loading a specific translation with no fallback. If an exception is raised, we then reduce the length of the language code to the first two characters, and attempt to load the translation while using gettext’s option of falling back to the hard-coded version if needed.
Important
By default, we should perhaps ask translators to provide generic 2-letter code versions for translations, so that a better fallback than the default English version could be found. See the related open question above, as to whether or not this should be provided in addition to any region specific version.
Other similar projects¶
Many other projects do some enhanced traceback formatting, however none that we know of aim at
making tracebacks easier to understand by beginners
translating traceback information.
Still, there is much to learn by looking at what others are doing. The following is an incomplete list of projects or modules to look at:
Todo
Add explanation about:
variable shown
how it works (especially for analysis of SyntaxError cases)
use Mu to show numbered prompt