Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Translate Python error messages #507

Open
gquintana opened this issue Jun 25, 2018 · 17 comments
Open

Translate Python error messages #507

gquintana opened this issue Jun 25, 2018 · 17 comments

Comments

@gquintana
Copy link
Contributor

After having tested my french translation on french teenagers, I noticed they don't understand Python error messages (when they click on verify) which are still in English.

I understand it's not possible to translate all Python error messages of all Python versions. But I wonder whether it could be possible to translate the most frequent ones (mostly syntax errors).

@ntoll
Copy link
Member

ntoll commented Jun 25, 2018

This is something I've been thinking about a LOT (see, for example, the tweets and replies here: https://twitter.com/ntoll/status/989149201090142208 -- my idea to replace the standard incomprehensible-to-learners error messages with something beginner friends [and thus also translatable]). I think this would take some coordination but is definitely something we should at least attempt to address. :-) Would love your input / ideas!

@aroberge
Copy link

This is something that is in principle possible to do but can be tricky. I've done something along these lines with Reeborg's World where I do try to provide some more meaningful (and translated!) error messages. Since this is a web version, the actual code to do this is Javascript and can be found at https://github.com/aroberge/reeborg/blob/master/src/js/runner/runner.js#L173

@ntoll
Copy link
Member

ntoll commented Jun 29, 2018

Ooooohh... @aroberge thanks for the heads up... we'll take a look at how you do it! ;-)

@aroberge
Copy link

Pure Python example: I also did it more than 10 years ago for my custom Exceptions with an attempt at providing some translated information for generic exceptions in rur-ple https://github.com/aroberge/rur-ple/blob/master/rur_py/cpu.py#L296

@ntoll
Copy link
Member

ntoll commented Jun 29, 2018

Thanks! :-)

@aroberge
Copy link

aroberge commented Jul 9, 2018

TigerJython (http://jython.tobiaskohn.ch/index.html) provides much simplified tracebacks, translated in various languages. The source code is not available (it appears to be a project part of a Ph.D. thesis) but perhaps the author might be willing to share some insights (if not some code) if he were to be contacted.

@ntoll
Copy link
Member

ntoll commented Jul 9, 2018

Yeah... I saw that via edu-sig. As far as I can tell it's built on Jython (i.e. Python running on the JVM) so my hunch is that error / exception handling will be JVM implementation specific and won't transfer well (if at all) to CPython. Here's hoping I'm wrong. :-)

@ZanderBrown
Copy link
Contributor

SyntaxError gets us halfway there to start with. Obviously a reasonable amount of .text trickery will be required (lots to translate...)

Without shipping a customised Cython build there is a limit to how much we can reliably do

@tmontes
Copy link
Member

tmontes commented Jul 17, 2018

A few thoughts on this topic:

  • Overriding sys.excepthook allows one to inspect/change exceptions and tracebacks (proof of concept below).
  • That does not require a customised CPython build; a customised site.py should be enough. It would just need to install a customised exception hook callable.
  • This should work when the bundled Python interpreter is used -- Python / Pygamezero mode. Not sure about MicroPython/CircuitPython: do those support any equivalent hooks?

Basic proof of concept:

import sys

def nicer_exception(exctype, value):

    HINT = 'Friendly hint message!'

    hinted_args = list(value.args)
    hinted_args[0] = f'{value.args[0]} - {HINT}'
    return exctype(*hinted_args)

def custom_except_hook(exctype, value, traceback):

    sys.__excepthook__(exctype, nicer_exception(exctype, value), traceback)

sys.excepthook = custom_except_hook

Now say that module is cem.py:

$ python -i cem.py
>>> 1/0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero - Friendly hint message!

>>> print("Hello)
  File "<stdin>", line 1
    print("Hello)
                ^
SyntaxError: EOL while scanning string literal - Friendly hint message!

Notes:

  • This sample assumes the exception object's .args[0] always exists and contains a message string (may not be true in some cases, in particular with custom exceptions).
  • It might be interesting to use a separate "hint" argument to the exceptions (an extra one, available at .args[-1], with a specific known type, and implement an alternative traceback print that could highlight the hint in different ways.
  • To activate this, importing cem in site.py should be enough.

After re-reading thought:

  • A cleaner approach might be to wrap exception in a HintedException which would track both the wrapped exception and the hint (probably a text string, maybe a URL?) as separate attributes. It could (should?) also have a customised __repr__ that would render both the wrapped exception and the hint in any way deemed appropriate -- again, needs some thinking. :)

@tmontes
Copy link
Member

tmontes commented Jul 17, 2018

Short update after a quick test on MicroPython 1.9.4:

  • The equivalent of CPython's sys.excepthook seems to be sys.print_exception.
  • From my quick experimentation, MicroPython does not allow assigning it to a different callable. :(

Here's my experimentation session transcript:

tiago.montes@rpi3:~/upython/micropython-1.9.4/ports/unix$ ./micropython 
MicroPython v1.9.4 on 2018-07-17; linux version
Use Ctrl-D to exit, Ctrl-E for paste mode
>>> import sys
>>> 1/0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
>>> try:
...     1/0
... except Exception as e:
...     print('Before')
...     sys.print_exception(e)
...     print('After')
... 
Before
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ZeroDivisionError: division by zero
After

Confirmed that sys.print_exception does what is expected of it. Let's try and change it:

>>> sys.print_exception = lambda e: print('Overriding!')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'print_exception'

No go! :(

@tim-mccurrach
Copy link
Contributor

I started having a go at doing this today. I really like the idea above of adding a hint and was thinking of adding on to the end of each error message, some clickable text, something like:
NameError: name ‘variable’ is not defined [Help on this error]
which when clicked would show a tooltip with a short explanation of common reasons why the error occurs, and what to look for in your code to fix the error. This way, before long, learners will understand how to read the standard errors, and not need the extra help. I feel this fits well with the philosophy (which I think I read somewhere) of mu training beginners so they will be able to go on and use more advanced editors.

What do others think of this? Good idea or does it add a lack-of-simplicity, that simply rewriting the messages would avoid?

I’m also conscious, that whilst the above addresses the issue of incomprehensible-to-beginners error messages, but doesn’t consider the issue of internationalization. I’d be keen to understand from someone who has more insight than me in this area:

  • given users won't necessarily have translated errors with other setups, would it be better to have just the additional help translated or the original error message as well?

  • And if so, would it be an advantage to have the whole trace translated as well as the final message?

@aroberge
Copy link

aroberge commented Aug 7, 2018 via email

@tannewt
Copy link
Contributor

tannewt commented Aug 8, 2018

Hey all, I just wanted to drop in and say I think this is a great idea! So great in fact I've added support for translated versions of CircuitPython. mu's internationalization was a big inspiration.

We'd love help with translation. I'm hopeless and only speak English. I've created this issue to track our translation effort. Thanks and keep up the great work.

@aroberge
Copy link

See https://github.com/aroberge/friendly-traceback for a separate project that could eventually provide the desired translations - and more. Friendly-traceback is being developed as a completely separate project while thinking of Mu as a possible application.

@ntoll
Copy link
Member

ntoll commented Apr 28, 2019

What's more, @aroberge has been wonderful and created some PyCon-sprint friendly issues in the linked-to repository. Looking forward to diving in and hopefully helping folks contribute. After @aroberge says "I'm happy with the 'alpha' state of the code" I want to get this into the alpha release of Mu. :-)

@aroberge
Copy link

@ntoll I think it is in a state where Friendly-traceback could already be of some benefit to beginners. The converse is certainly true: Friendly-traceback could definitely benefit from feedback from actual users.

I'm aiming to add at least two additional cases (single exceptions, additional source of SyntaxError with explanation, etc.) per day for the next little while. I do not have any specific plans for new releases on pypi. If such a release would be useful, please let me know.

@ntoll
Copy link
Member

ntoll commented Apr 29, 2019

@aroberge 👍 The PyCon Sprints start next Monday, and I hope to direct folks to friendly-tracebacks and incorporate it into Mu during the course of said sprints. Upon my return I'd like to release 1.1-alpha.2 version of Mu. :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants