Warning

This project is being split into 3 separate projects:

  • friendly_traceback,

  • friendly, and

  • friendly_idle.

The documentation does not reflect this change.

If you are a end-user, just install friendly until further notice.

Some thoughts on the design of friendly

The following are thoughts on the design of this project. The content of this file will be changed as this project evolve.

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.

_images/thonny.png

For now, friendly tries to identify the most likely cause of the exception, but some consideration has been given to include more than one possible explanation in some 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 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.

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.

IndexError traceback

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.

IndexError traceback

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.

SyntaxError traceback

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

  1. making tracebacks easier to understand by beginners

  2. 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: