python-babel / babel

The official repository for Babel, the Python Internationalization Library
http://babel.pocoo.org/
BSD 3-Clause "New" or "Revised" License
1.29k stars 432 forks source link

Hide extensive traceback from the user and show only relevant information #1049

Closed tomschr closed 6 months ago

tomschr commented 6 months ago

Overview Description

Thank you for all your efforts in creating and maintaining this project. :+1:

Steps to Reproduce

  1. Prepare the environment:

    $ python3 --version Python 3.12.1 $ mkdir /tmp/test-pybabel $ python3 -m venv .venv $ source .venv/bin/activate $ pip install pybabel Jinja2 $ pip install --upgrade pip setuptools $ pip list Package Version


    Jinja2 3.1.2 MarkupSafe 2.1.3 pip 23.3.1 pybabel 0.0.0.dev0 setuptools 69.0.2

  2. Create a Jinja2 template test.html.jinja2 with the following wrong(!) content:

    <html>
     <title>{% trans %}Hello World{% trans %}</title>
     <body>
       <h1>{% trans %}Welcome!{% endtrans %}</h1>
     </body>
    </html>
  3. Create a babel.cfg file with the following content:

    [jinja2: **.html.jinja2]
    encoding = utf-8
    ignore_tags = script,style
    include_attrs = alt title summary
    keyword = trans
    silent = false
  4. Extract the translatable strings

    $ pybabel extract -F babel.cfg -o test.pot *.html.jinja2
    [... very long traceback ...]
    File "/home/tux/.pyenv/versions/3.12.1/lib/python3.12/site-packages/jinja2/environment.py", line 611, in parse
      self.handle_exception(source=source)
    File "/home/tux/.pyenv/versions/3.12.1/lib/python3.12/site-packages/jinja2/environment.py", line 936, in handle_exception
    raise rewrite_traceback_stack(source=source)
    File "<unknown>", line 2, in template
    jinja2.exceptions.TemplateSyntaxError: control structures in translatable sections are not allowed

Actual Results

An (ugly) traceback shown to the user (as presented in step 4).

Expected Results

I'm aware that the silent keyword in babel.cfg leads to this kind of error. However, nevertheless I see an issue when showing the complete traceback to the user:

All these points make it more difficult for the user to extract the relevant information.

In my opinion, a verbose traceback output should never be shown to the user unless there is really something fundamentally wrong. A syntax problem in a Jinja2 template should not lead to this extensive traceback output and should be condensed to the important information.

In other words, I expected something more user-friendly. :slightly_smiling_face:

For example, pybabel should show the relevant information only which is:

Here is one idea how it could be shown to the user:

$ pybable extract ...
jinja2.exceptions.TemplateSyntaxError (line 2): control structures in translatable sections are not allowed

The real output is subject for another discussion. :wink: But I think you get the idea.

If you want to make it even more useful, suggest a solution to this problem:

$ pybable extract ...
inja2.exceptions.TemplateSyntaxError: line 2 control structures in translatable sections are not allowed
For more information, see <URL>.

The URL could point to a GitHub Wiki in your repo or the actual documentation. The content should show the most common problem and how to solve it. Each content should be consistent to each other and should have the same structure. For example:

Problem
Control structures in translatable sections are not allowed

Cause
Pybabel found ...

Solution
Try the following steps to find the root cause:
1. First step
2. Second step
3. Third step

Reproducibility

See above.

Additional Information

n/a

akx commented 6 months ago

Thank you for the comprehensive issue report!

As an aside, pybabel is an unrelated (and evidently abandoned) project; we're babel and our CLI tool happens to be named pybabel for some historical reasons I'm not aware of.

Given Babel is fundamentally a technical tool aimed at somewhat technical users, I'd rather not try to smooth over the long error, lest we end up with a babel did an oopsie woopsie situation.

I'd also rather not try to be clever about redacting the traceback, since more often than not it offers valuable clues as to what has actually gone wrong when an user reaches out to the Babel folks – asking the user to re-run the command with something like --verbose-traceback or whatever sounds like more trouble than it's worth too.

Not to shift blame but to clarify the situation, the actual error you're seeing here stems from Jinja, as it's trying to parse your template: https://github.com/pallets/jinja/blob/d594969d722ceb4e8f3da8861befc9c0ac87ae1b/src/jinja2/ext.py#L506-L508

You would get the same error without Babel in-between:

>>> import jinja2
>>> from jinja2.ext import InternationalizationExtension
>>> e = jinja2.Environment(extensions=[InternationalizationExtension])
>>> e.from_string("{% trans %}Hello World{% trans %}")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.12/site-packages/jinja2/environment.py", line 1105, in from_string
    return cls.from_code(self, self.compile(source), gs, None)
                               ^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/jinja2/environment.py", line 768, in compile
    self.handle_exception(source=source_hint)
  File "/usr/local/lib/python3.12/site-packages/jinja2/environment.py", line 936, in handle_exception
    raise rewrite_traceback_stack(source=source)
  File "<unknown>", line 1, in template
jinja2.exceptions.TemplateSyntaxError: control structures in translatable sections are not allowed
>>>

It would of course be useful if that Jinja syntax error noted the name of the control structure, e.g.

jinja2.exceptions.TemplateSyntaxError: control structures in translatable sections are not allowed (saw trans)

or better yet, for this particular case,

jinja2.exceptions.TemplateSyntaxError: trans blocks may not be nested (did you mean endtrans?)

but that's not in Babel's control; adding logic that would sniff out this situation from a Jinja-specific exception and show it differently sounds brittle.

To that end, I opened a PR in Jinja that makes these errors nicer. https://github.com/pallets/jinja/pull/1918

tomschr commented 6 months ago

Thank you for your answers! Appreciated your response.

As an aside, pybabel is an unrelated (and evidently abandoned) project; we're babel and our CLI tool happens to be named pybabel for some historical reasons I'm not aware of.

Oh, I wasn't aware of that. :astonished: Is there are replacement for pybabel? Anything you can recommend?

I'd also rather not try to be clever about redacting the traceback, since more often than not it offers valuable clues as to what has actually gone wrong when an user reaches out to the Babel folks – asking the user to re-run the command with something like --verbose-traceback or whatever sounds like more trouble than it's worth too.

I see what you mean. I was looking at it from a pure user point of view.

Thanks for opening an issue for the Jinja project.

Maybe in this case, I better close this issue.

Thanks for all your help! :+1:

akx commented 6 months ago

As an aside, pybabel is an unrelated (and evidently abandoned) project; we're babel and our CLI tool happens to be named pybabel for some historical reasons I'm not aware of.

Oh, I wasn't aware of that. 😲 Is there are replacement for pybabel? Anything you can recommend?

Oh no, what I mean is that the pybabel PyPI package is unrelated to this project and repository. This project is not abandoned.

You install the pybabel tool from this repository by running pip install babel:

# pip install babel
Successfully installed babel-2.14.0
# pybabel
Usage: pybabel command [options] [args]

pybabel: error: no valid command or option passed. Try the -h/--help option for more information.
#

c.f. installing pybabel, which does nothing of value:

# pip install pybabel
Successfully installed pybabel-0.0.0.dev0
# pybabel
bash: pybabel: command not found
#

(In fact, all that package contains is an empty babel.py file... 🤷)

tomschr commented 6 months ago

Thanks for the clarification. Much appreciated. :+1: