Skip to content

Commit

Permalink
Add support for python-brace-format
Browse files Browse the repository at this point in the history
  • Loading branch information
tomasr8 committed Jan 12, 2025
1 parent c2b397e commit 08512c7
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 0 deletions.
29 changes: 29 additions & 0 deletions babel/messages/catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from difflib import SequenceMatcher
from email import message_from_string
from heapq import nlargest
from string import Formatter
from typing import TYPE_CHECKING

from babel import __version__ as VERSION
Expand Down Expand Up @@ -69,6 +70,15 @@ def get_close_matches(word, possibilities, n=3, cutoff=0.6):
''', re.VERBOSE)


def _has_python_brace_format(string: str) -> bool:
fmt = Formatter()
try:
parsed = list(fmt.parse(string))
except ValueError:
return False
return any(True for _, field_name, *_ in parsed if field_name is not None)


def _parse_datetime_header(value: str) -> datetime.datetime:
match = re.match(r'^(?P<datetime>.*?)(?P<tzoffset>[+-]\d{4})?$', value)

Expand Down Expand Up @@ -140,6 +150,10 @@ def __init__(
self.flags.add('python-format')
else:
self.flags.discard('python-format')
if id and self.python_brace_format:
self.flags.add('python-brace-format')
else:
self.flags.discard('python-brace-format')
self.auto_comments = list(distinct(auto_comments))
self.user_comments = list(distinct(user_comments))
if isinstance(previous_id, str):
Expand Down Expand Up @@ -252,6 +266,21 @@ def python_format(self) -> bool:
ids = [ids]
return any(PYTHON_FORMAT.search(id) for id in ids)

@property
def python_brace_format(self) -> bool:
"""Whether the message contains Python f-string parameters.
>>> Message('Hello, {name}!').python_brace_format
True
>>> Message(('One apple', '{count} apples')).python_brace_format
True
:type: `bool`"""
ids = self.id
if not isinstance(ids, (list, tuple)):
ids = [ids]
return any(_has_python_brace_format(id) for id in ids)


class TranslationError(Exception):
"""Exception thrown by translation checkers when invalid message
Expand Down
27 changes: 27 additions & 0 deletions tests/messages/test_catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,24 @@ def test_python_format(self):
assert catalog.PYTHON_FORMAT.search('foo %(name)*.*f')
assert catalog.PYTHON_FORMAT.search('foo %()s')

def test_python_brace_format(self):
assert not catalog._has_python_brace_format('')
assert not catalog._has_python_brace_format('foo')
assert not catalog._has_python_brace_format('{')
assert not catalog._has_python_brace_format('}')
assert not catalog._has_python_brace_format('{} {')
assert not catalog._has_python_brace_format('{{}}')
assert catalog._has_python_brace_format('{}')
assert catalog._has_python_brace_format('foo {name}')
assert catalog._has_python_brace_format('foo {name!s}')
assert catalog._has_python_brace_format('foo {name!r}')
assert catalog._has_python_brace_format('foo {name!a}')
assert catalog._has_python_brace_format('foo {name!r:10}')
assert catalog._has_python_brace_format('foo {name!r:10.2}')
assert catalog._has_python_brace_format('foo {name!r:10.2f}')
assert catalog._has_python_brace_format('foo {name!r:10.2f} {name!r:10.2f}')
assert catalog._has_python_brace_format('foo {name!r:10.2f=}')

def test_translator_comments(self):
mess = catalog.Message('foo', user_comments=['Comment About `foo`'])
assert mess.user_comments == ['Comment About `foo`']
Expand Down Expand Up @@ -342,10 +360,19 @@ def test_message_pluralizable():


def test_message_python_format():
assert not catalog.Message('foo').python_format
assert not catalog.Message(('foo', 'foo')).python_format
assert catalog.Message('foo %(name)s bar').python_format
assert catalog.Message(('foo %(name)s', 'foo %(name)s')).python_format


def test_message_python_brace_format():
assert not catalog.Message('foo').python_brace_format
assert not catalog.Message(('foo', 'foo')).python_brace_format
assert catalog.Message('foo {name} bar').python_brace_format
assert catalog.Message(('foo {name}', 'foo {name}')).python_brace_format


def test_catalog():
cat = catalog.Catalog(project='Foobar', version='1.0',
copyright_holder='Foo Company')
Expand Down

0 comments on commit 08512c7

Please sign in to comment.