Skip to content

Commit

Permalink
Replace %/.format/concatenation with f-strings where feasible (#927)
Browse files Browse the repository at this point in the history
Original conversion suggestions via flynt, edited by hand.
  • Loading branch information
akx committed Nov 23, 2022
1 parent 896c2ea commit a45e25e
Show file tree
Hide file tree
Showing 24 changed files with 161 additions and 204 deletions.
15 changes: 7 additions & 8 deletions babel/core.py
Expand Up @@ -98,7 +98,7 @@ def __init__(self, identifier):
:param identifier: the identifier string of the unsupported locale
"""
Exception.__init__(self, 'unknown locale %r' % identifier)
Exception.__init__(self, f"unknown locale {identifier!r}")

#: The identifier of the locale that could not be found.
self.identifier = identifier
Expand Down Expand Up @@ -262,7 +262,7 @@ def parse(cls, identifier, sep='_', resolve_likely_subtags=True):
elif isinstance(identifier, Locale):
return identifier
elif not isinstance(identifier, str):
raise TypeError('Unexpected value for identifier: %r' % (identifier,))
raise TypeError(f"Unexpected value for identifier: {identifier!r}")

parts = parse_locale(identifier, sep=sep)
input_id = get_locale_identifier(parts)
Expand Down Expand Up @@ -349,9 +349,8 @@ def __repr__(self):
for key in ('territory', 'script', 'variant'):
value = getattr(self, key)
if value is not None:
parameters.append('%s=%r' % (key, value))
parameter_string = '%r' % self.language + ', '.join(parameters)
return 'Locale(%s)' % parameter_string
parameters.append(f"{key}={value!r}")
return f"Locale({self.language!r}{', '.join(parameters)})"

def __str__(self):
return get_locale_identifier((self.language, self.territory,
Expand Down Expand Up @@ -388,7 +387,7 @@ def get_display_name(self, locale=None):
details.append(locale.variants.get(self.variant))
details = filter(None, details)
if details:
retval += ' (%s)' % u', '.join(details)
retval += f" ({', '.join(details)})"
return retval

display_name = property(get_display_name, doc="""\
Expand Down Expand Up @@ -1120,7 +1119,7 @@ def parse_locale(identifier, sep='_'):
parts = identifier.split(sep)
lang = parts.pop(0).lower()
if not lang.isalpha():
raise ValueError('expected only letters, got %r' % lang)
raise ValueError(f"expected only letters, got {lang!r}")

script = territory = variant = None
if parts:
Expand All @@ -1139,7 +1138,7 @@ def parse_locale(identifier, sep='_'):
variant = parts.pop().upper()

if parts:
raise ValueError('%r is not a valid locale identifier' % identifier)
raise ValueError(f"{identifier!r} is not a valid locale identifier")

return lang, territory, script, variant

Expand Down
27 changes: 11 additions & 16 deletions babel/dates.py
Expand Up @@ -203,7 +203,7 @@ def get_timezone(zone=None):
try:
return _pytz.timezone(zone)
except _pytz.UnknownTimeZoneError:
raise LookupError('Unknown timezone %s' % zone)
raise LookupError(f"Unknown timezone {zone}")


def get_next_timezone_transition(zone=None, dt=None):
Expand Down Expand Up @@ -312,11 +312,7 @@ def to_offset(self):
return int(self.to_tzinfo._utcoffset.total_seconds())

def __repr__(self):
return '<TimezoneTransition %s -> %s (%s)>' % (
self.from_tz,
self.to_tz,
self.activates,
)
return f"<TimezoneTransition {self.from_tz} -> {self.to_tz} ({self.activates})>"


def get_period_names(width='wide', context='stand-alone', locale=LC_TIME):
Expand Down Expand Up @@ -958,7 +954,7 @@ def _iter_patterns(a_unit):
yield unit_rel_patterns['future']
else:
yield unit_rel_patterns['past']
a_unit = 'duration-' + a_unit
a_unit = f"duration-{a_unit}"
yield locale._data['unit_patterns'].get(a_unit, {}).get(format)

for unit, secs_per_unit in TIMEDELTA_UNITS:
Expand Down Expand Up @@ -1293,7 +1289,7 @@ def __init__(self, pattern, format):
self.format = format

def __repr__(self):
return '<%s %r>' % (type(self).__name__, self.pattern)
return f"<{type(self).__name__} {self.pattern!r}>"

def __str__(self):
pat = self.pattern
Expand Down Expand Up @@ -1365,7 +1361,7 @@ def __getitem__(self, name):
elif char in ('z', 'Z', 'v', 'V', 'x', 'X', 'O'):
return self.format_timezone(char, num)
else:
raise KeyError('Unsupported date/time field %r' % char)
raise KeyError(f"Unsupported date/time field {char!r}")

def extract(self, char):
char = str(char)[0]
Expand All @@ -1384,7 +1380,7 @@ def extract(self, char):
elif char == 'a':
return int(self.value.hour >= 12) # 0 for am, 1 for pm
else:
raise NotImplementedError("Not implemented: extracting %r from %r" % (char, self.value))
raise NotImplementedError(f"Not implemented: extracting {char!r} from {self.value!r}")

def format_era(self, char, num):
width = {3: 'abbreviated', 4: 'wide', 5: 'narrow'}[max(3, num)]
Expand Down Expand Up @@ -1429,7 +1425,7 @@ def format_week(self, char, num):
if week == 0:
date = self.value - timedelta(days=self.value.day)
week = self.get_week_number(date.day, date.weekday())
return '%d' % week
return str(week)

def format_weekday(self, char='E', num=4):
"""
Expand Down Expand Up @@ -1475,7 +1471,7 @@ def format_day_of_year(self, num):
return self.format(self.get_day_of_year(), num)

def format_day_of_week_in_month(self):
return '%d' % ((self.value.day - 1) // 7 + 1)
return str((self.value.day - 1) // 7 + 1)

def format_period(self, char, num):
"""
Expand Down Expand Up @@ -1517,7 +1513,7 @@ def format_period(self, char, num):
period_names = get_period_names(context=context, width=width, locale=self.locale)
if period in period_names:
return period_names[period]
raise ValueError('Could not format period %s in %s' % (period, self.locale))
raise ValueError(f"Could not format period {period} in {self.locale}")

def format_frac_seconds(self, num):
""" Return fractional seconds.
Expand Down Expand Up @@ -1689,11 +1685,10 @@ def parse_pattern(pattern):
fieldchar, fieldnum = tok_value
limit = PATTERN_CHARS[fieldchar]
if limit and fieldnum not in limit:
raise ValueError('Invalid length for field: %r'
% (fieldchar * fieldnum))
raise ValueError(f"Invalid length for field: {fieldchar * fieldnum!r}")
result.append('%%(%s)s' % (fieldchar * fieldnum))
else:
raise NotImplementedError("Unknown token type: %s" % tok_type)
raise NotImplementedError(f"Unknown token type: {tok_type}")

_pattern_cache[pattern] = pat = DateTimePattern(pattern, u''.join(result))
return pat
Expand Down
9 changes: 4 additions & 5 deletions babel/lists.py
Expand Up @@ -68,11 +68,10 @@ def format_list(lst, style='standard', locale=DEFAULT_LOCALE):
return lst[0]

if style not in locale.list_patterns:
raise ValueError('Locale %s does not support list formatting style %r (supported are %s)' % (
locale,
style,
list(sorted(locale.list_patterns)),
))
raise ValueError(
f'Locale {locale} does not support list formatting style {style!r} '
f'(supported are {sorted(locale.list_patterns)})'
)
patterns = locale.list_patterns[style]

if len(lst) == 2:
Expand Down
6 changes: 3 additions & 3 deletions babel/localedata.py
Expand Up @@ -50,10 +50,10 @@ def resolve_locale_filename(name):

# Ensure we're not left with one of the Windows reserved names.
if sys.platform == "win32" and _windows_reserved_name_re.match(os.path.splitext(name)[0]):
raise ValueError("Name %s is invalid on Windows" % name)
raise ValueError(f"Name {name} is invalid on Windows")

# Build the path.
return os.path.join(_dirname, '%s.dat' % name)
return os.path.join(_dirname, f"{name}.dat")


def exists(name):
Expand Down Expand Up @@ -194,7 +194,7 @@ def __init__(self, keys):
self.keys = tuple(keys)

def __repr__(self):
return '<%s %r>' % (type(self).__name__, self.keys)
return f"<{type(self).__name__} {self.keys!r}>"

def resolve(self, data):
"""Resolve the alias based on the given data.
Expand Down
4 changes: 2 additions & 2 deletions babel/localtime/_win32.py
Expand Up @@ -77,11 +77,11 @@ def get_localzone_name():
if timezone is None:
# Nope, that didn't work. Try adding 'Standard Time',
# it seems to work a lot of times:
timezone = tz_names.get(tzkeyname + ' Standard Time')
timezone = tz_names.get(f"{tzkeyname} Standard Time")

# Return what we have.
if timezone is None:
raise pytz.UnknownTimeZoneError('Can not find timezone ' + tzkeyname)
raise pytz.UnknownTimeZoneError(f"Can not find timezone {tzkeyname}")

return timezone

Expand Down
32 changes: 14 additions & 18 deletions babel/messages/catalog.py
Expand Up @@ -49,7 +49,7 @@ def _parse_datetime_header(value):
hours_offset_s, mins_offset_s = rest[:2], rest[2:]

# Make them all integers
plus_minus = int(plus_minus_s + '1')
plus_minus = int(f"{plus_minus_s}1")
hours_offset = int(hours_offset_s)
mins_offset = int(mins_offset_s)

Expand Down Expand Up @@ -108,8 +108,7 @@ def __init__(self, id, string=u'', locations=(), flags=(), auto_comments=(),
self.context = context

def __repr__(self):
return '<%s %r (flags: %r)>' % (type(self).__name__, self.id,
list(self.flags))
return f"<{type(self).__name__} {self.id!r} (flags: {list(self.flags)!r})>"

def __cmp__(self, other):
"""Compare Messages, taking into account plural ids"""
Expand Down Expand Up @@ -312,7 +311,7 @@ def _set_locale(self, locale):
self._locale = None
return

raise TypeError('`locale` must be a Locale, a locale identifier string, or None; got %r' % locale)
raise TypeError(f"`locale` must be a Locale, a locale identifier string, or None; got {locale!r}")

def _get_locale(self):
return self._locale
Expand All @@ -334,7 +333,7 @@ def _get_header_comment(self):
.replace('ORGANIZATION', self.copyright_holder)
locale_name = (self.locale.english_name if self.locale else self.locale_identifier)
if locale_name:
comment = comment.replace('Translations template', '%s translations' % locale_name)
comment = comment.replace("Translations template", f"{locale_name} translations")
return comment

def _set_header_comment(self, string):
Expand Down Expand Up @@ -375,8 +374,7 @@ def _set_header_comment(self, string):

def _get_mime_headers(self):
headers = []
headers.append(('Project-Id-Version',
'%s %s' % (self.project, self.version)))
headers.append(("Project-Id-Version", f"{self.project} {self.version}"))
headers.append(('Report-Msgid-Bugs-To', self.msgid_bugs_address))
headers.append(('POT-Creation-Date',
format_datetime(self.creation_date, 'yyyy-MM-dd HH:mmZ',
Expand All @@ -399,10 +397,9 @@ def _get_mime_headers(self):
if self.locale is not None:
headers.append(('Plural-Forms', self.plural_forms))
headers.append(('MIME-Version', '1.0'))
headers.append(('Content-Type',
'text/plain; charset=%s' % self.charset))
headers.append(("Content-Type", f"text/plain; charset={self.charset}"))
headers.append(('Content-Transfer-Encoding', '8bit'))
headers.append(('Generated-By', 'Babel %s\n' % VERSION))
headers.append(("Generated-By", f"Babel {VERSION}\n"))
return headers

def _force_text(self, s, encoding='utf-8', errors='strict'):
Expand Down Expand Up @@ -434,7 +431,7 @@ def _set_mime_headers(self, headers):
if 'charset' in params:
self.charset = params['charset'].lower()
elif name == 'plural-forms':
params = parse_separated_header(' ;' + value)
params = parse_separated_header(f" ;{value}")
self._num_plurals = int(params.get('nplurals', 2))
self._plural_expr = params.get('plural', '(n != 1)')
elif name == 'pot-creation-date':
Expand Down Expand Up @@ -541,7 +538,7 @@ def plural_forms(self):
'nplurals=2; plural=(n > 1);'
:type: `str`"""
return 'nplurals=%s; plural=%s;' % (self.num_plurals, self.plural_expr)
return f"nplurals={self.num_plurals}; plural={self.plural_expr};"

def __contains__(self, id):
"""Return whether the catalog has a message with the specified ID."""
Expand All @@ -560,7 +557,7 @@ def __iter__(self):
:rtype: ``iterator``"""
buf = []
for name, value in self.mime_headers:
buf.append('%s: %s' % (name, value))
buf.append(f"{name}: {value}")
flags = set()
if self.fuzzy:
flags |= {'fuzzy'}
Expand All @@ -571,8 +568,8 @@ def __iter__(self):
def __repr__(self):
locale = ''
if self.locale:
locale = ' %s' % self.locale
return '<%s %r%s>' % (type(self).__name__, self.domain, locale)
locale = f" {self.locale}"
return f"<{type(self).__name__} {self.domain!r}{locale}>"

def __delitem__(self, id):
"""Delete the message with the specified ID."""
Expand Down Expand Up @@ -626,13 +623,12 @@ def __setitem__(self, id, message):
elif id == '':
# special treatment for the header message
self.mime_headers = message_from_string(message.string).items()
self.header_comment = '\n'.join([('# %s' % c).rstrip() for c
in message.user_comments])
self.header_comment = "\n".join([f"# {c}".rstrip() for c in message.user_comments])
self.fuzzy = message.fuzzy
else:
if isinstance(id, (list, tuple)):
assert isinstance(message.string, (list, tuple)), \
'Expected sequence but got %s' % type(message.string)
f"Expected sequence but got {type(message.string)}"
self._messages[key] = message

def add(self, id, string=None, locations=(), flags=(), auto_comments=(),
Expand Down
2 changes: 1 addition & 1 deletion babel/messages/checkers.py
Expand Up @@ -144,7 +144,7 @@ def _check_positional(results):
type_map = dict(a)
for name, typechar in b:
if name not in type_map:
raise TranslationError('unknown named placeholder %r' % name)
raise TranslationError(f'unknown named placeholder {name!r}')
elif not _compatible(typechar, type_map[name]):
raise TranslationError('incompatible format for '
'placeholder %r: '
Expand Down
13 changes: 6 additions & 7 deletions babel/messages/extract.py
Expand Up @@ -42,9 +42,6 @@

DEFAULT_MAPPING = [('**.py', 'python')]

empty_msgid_warning = (
'%s: warning: Empty msgid. It is reserved by GNU gettext: gettext("") '
'returns the header entry with meta information, not the empty string.')


def _strip_comment_tags(comments, tags):
Expand Down Expand Up @@ -332,7 +329,7 @@ def extract(method, fileobj, keywords=DEFAULT_KEYWORDS, comment_tags=(),
func = builtin.get(method)

if func is None:
raise ValueError('Unknown extraction method %r' % method)
raise ValueError(f"Unknown extraction method {method!r}")

results = func(fileobj, keywords.keys(), comment_tags,
options=options or {})
Expand Down Expand Up @@ -377,9 +374,11 @@ def extract(method, fileobj, keywords=DEFAULT_KEYWORDS, comment_tags=(),
first_msg_index = spec[0] - 1
if not messages[first_msg_index]:
# An empty string msgid isn't valid, emit a warning
where = '%s:%i' % (hasattr(fileobj, 'name') and
fileobj.name or '(unknown)', lineno)
sys.stderr.write((empty_msgid_warning % where) + '\n')
filename = (getattr(fileobj, "name", None) or "(unknown)")
sys.stderr.write(
f"{filename}:{lineno}: warning: Empty msgid. It is reserved by GNU gettext: gettext(\"\") "
f"returns the header entry with meta information, not the empty string.\n"
)
continue

messages = tuple(msgs)
Expand Down

0 comments on commit a45e25e

Please sign in to comment.