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

gh-130453: pygettext: Extend support for specifying custom keywords #130463

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

tomasr8
Copy link
Member

@tomasr8 tomasr8 commented Feb 22, 2025

This addresses the first point in #130453

It is now possible to use the full keyword spec syntax (except for t, that will be added later) to specify keywords:

./python Tools/i18n/pygettext.py --keyword=foo:1
./python Tools/i18n/pygettext.py --keyword=foo:1,2
./python Tools/i18n/pygettext.py --keyword=foo:1c,2
./python Tools/i18n/pygettext.py --keyword=foo:1c,2,3

I tried to match the behaviour of xgettext and babel but neither seem to do much validation for the keyword specs.
xgettext, for instance, does not allow foo:1c,2c (context specified twice) nor foo:1,1c (msgid and msgctxt have the same index) but it does (weirdly) allow foo:1,1 (same index for msgid and msgid_plural), whereas it outright crashes with a double free for foo:1,1,2c.

This PR properly validates the keyword specs in order to be consistent and provide helpful error messages to the user.

Feedback welcome!

Copy link
Member

@serhiy-storchaka serhiy-storchaka left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not think that it was necessary to go so far with detecting errors and generating error reports. Garbage in -- garbage out. The parsing code could be 2 or 3 times smaller without this. But if you already implemented this, it is fine.

LGTM.

Comment on lines +355 to +356
for k, v in result.items():
if v == pos:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if pos in result.values():

raise ValueError(f'Invalid keyword spec {spec!r}: '
'msgctxt cannot appear without msgid')

return name, {v: k for k, v in result.items()}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be simpler to build result in that form from the beginning?

try:
options.keywords = dict(parse_spec(spec) for spec in options.keywords)
except ValueError as e:
raise SystemExit(e)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Other errors cause print() + sys.exit(1).

@@ -602,7 +685,7 @@ class Options:
elif opt in ('-D', '--docstrings'):
options.docstrings = 1
elif opt in ('-k', '--keyword'):
options.keywords.append(arg)
options.keywords.add(arg)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if you specify the same name twice with different specs? --keyword=gt:1 --keyword=gt:2? Set does not preserve order, so the end result is unpredicable.

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

Successfully merging this pull request may close these issues.

2 participants