Tuesday, December 28, 2021

New milestone for friendly: version 0.5

 Friendly (previously at 0.4.41) and friendly-traceback (previously at 0.4.111) are now at version 0.5. The joint documentation for both projects has not yet been updated.  In addition to the many new cases added for which friendly/friendly-traceback can help with, which includes close to 400 test cases, I am very excited to report to three new important features

  1. Getting help when a traceback is generated before friendly is imported
  2. Not having to set non-default configurations each time friendly is used
  3. The addition of two new languages.

1. Getting help after the fact


Let's start with the first.  Previously, if one wanted help from friendly/friendly-traceback, it had either to be used to run a program, via something like "python -m friendly user_program.py", or it had to be imported and installed (either implicitly or explicitly) before any other code was executed. This still works as before and is the best way to use friendly.

Now, it can be imported *after* a traceback has been generated, and can provide its usual help when using:
  • IPython in a terminal
  • Jupyter notebooks, and Jupyter lab
  • Mu
  • Programs run with cPython using "python -i user_program.py"
  • Code entered in a cPython terminal, with the caveat that it only works in a limited fashion for some SyntaxErrors but almost never for run time errors.
    • The same when using pypy with the exception that using languages other than English may yield some undesirable results.
  • Code saved in files and run from IDLE  (Python 3.10 and possibly later versions of Python 3.9) -- but excluding SyntaxErrors
  • Code entered in IDLE's shell - but excluding SyntaxErrors.
Before explaining the origin of the (different) limitations when using cPython's interactive interpreter or IDLE, let me show the results using IPython, both for SyntaxErrors and run time errors starting with a very unlikely example of SyntaxError


Of course, we can ask for more details

Instead of a SyntaxError, let's see an example of a run time error.

Again, it just works. :-)

Moving on to SyntaxErrors with the cPython interpreter. Let's use the same example as above, with Python 3.10.1:


This works. However, let's have a more detailed look at the information available:


Python does not store the content of the code entered in the interpreter; for SyntaxErrors, it does include the very last line of code where the error was located. This will not work in other situations where a statement spans multiple lines; in some cases, if the error message is precise enough, friendly might still be able to guess the cause of the error.



By contrast, friendly does store the entire code entered in its interpreter.


Let's have a look at a run time error with cPython.

Notice how the traceback contains no information about the code in the file(s) named "<stdin>".
Let's see what information we can get from friendly.


If you use friendly, you would never see the log message (1) as it is something that is enabled by default on my computer. Note that, in spite of not having access to the exact code that produced the exception, in this case friendly is still able to provide some help. This information is similar to what is available with Python 3.10+; however, you can use friendly with Python 3.6 and still get the same information!
Of course, it is better still if you use friendly from the start:





Let's now have a look at IDLE. Recently, IDLE has added support for custom exception hook. Instead of requiring the use of its own console when using IDLE, friendly can make use of this new capability of IDLE to provide help with run time errors - but not SyntaxErrors as those are handled in a peculiar way by IDLE.



For this type of error, trying to use friendly after the fact yields very little useful information.

For SyntaxErrors, the situation is even worse: IDLE does not make any information available.

1.a) A possible improvement to fix the problem with cPython

If you look at the tracebacks from IDLE for runtime errors, you will see "files" with names like 
"<pyshell#4>": each code block entered by the user is saved in such a "file", each file having a different name.  IDLE works around a limitation of Python's linecache module to store the content of these files so that they can be retrieved and analyzed.  By contrast, cPython shows the code entered by a user as belonging to files with identical names "<stdin>" whose content can never be retrieved.

For code executed using exec("code"), the content is shown to belong to a file named "<string>" whose content is also not available.  If cPython were to store the code in files whose named included a different integer each time, like IDLE does, then it could be retrieved by programs like friendly and provide additional help.  This was suggested on Python-ideas for code run using exec, but got not traction, even though related questions are often asked on StackOverflow.

Moving on ...

2. Friendly saves settings

Previously, each time that friendly was used, it started with default values for the preferred language (French and English only in previous versions), color scheme (light or dark, depending on the background of the terminal or other application), formatter type, etc.

Now, friendly saves the values specified which are then used by default when a new session starts. For the language choice, this is a global settings, that carries in all environments.  For other settings, friendly (at least on Windows) can determine if it is running in a PowerShell terminal or an old-fashion cmd, in a Visual Studio Code terminal, in a PyCharm terminal, if it is run with IPython, or in a Jupyter notebook, etc.   Here's an example of adjusting the background color so that the information provided by friendly blends in better.

Friendly only includes two different color scheme: one that is designed to work with a white (or similar) background and another with a black (or similar) background.  Anyone working with terminals (or notebooks) with background colors that do not work well with either of the two existing color schemes is welcome to provide different color schemes to be added to friendly.

So far, I have only tested this with Windows. Mac and Linux users are encouraged to try it out and see if their different environments can be detected correctly so that friendly can work well in all the environment they use it.


3. New languages

In addition to English and French, friendly is available in Spanish (approximately 99% of the translation is done, as I keep adding new information) and about 10% has been translated into Italian.

Conclusion

There is much more I could write about new but smaller additions to friendly since version 0.4.  However, this blog post is already too long and this will have to wait until later - perhaps after I update the existing documentation.