gh-104400: Remove `fintl.gettext` from pygettext (#129580)

The ``fintl`` module is never installed or tested, meaning that the
fallback identity function is unconditionally used for ``_()``.
This means we can simplify, converting the docstring to a real
docstring, and converting some other strings to f-strings.

We also convert the module to UTF-8, sort imports,
and remove the history comment, which was last updated in 2002.
Consult the git history for a more accurate summary of changes.
This commit is contained in:
Adam Turner 2025-02-02 14:30:34 +00:00 committed by GitHub
parent df4a2f5bd7
commit 237f186da4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1,26 +1,6 @@
#! /usr/bin/env python3 #! /usr/bin/env python3
# -*- coding: iso-8859-1 -*-
# Originally written by Barry Warsaw <barry@python.org>
#
# Minimally patched to make it even more xgettext compatible
# by Peter Funk <pf@artcom-gmbh.de>
#
# 2002-11-22 Jürgen Hermann <jh@web.de>
# Added checks that _() only contains string literals, and
# command line args are resolved to module lists, i.e. you
# can now pass a filename, a module or package name, or a
# directory (including globbing chars, important for Win32).
# Made docstring fit in 80 chars wide displays using pydoc.
#
# for selftesting """pygettext -- Python equivalent of xgettext(1)
try:
import fintl
_ = fintl.gettext
except ImportError:
_ = lambda s: s
__doc__ = _("""pygettext -- Python equivalent of xgettext(1)
Many systems (Solaris, Linux, Gnu) provide extensive tools that ease the Many systems (Solaris, Linux, Gnu) provide extensive tools that ease the
internationalization of C programs. Most of these tools are independent of internationalization of C programs. Most of these tools are independent of
@ -153,16 +133,16 @@ Options:
conjunction with the -D option above. conjunction with the -D option above.
If `inputfile' is -, standard input is read. If `inputfile' is -, standard input is read.
""") """
import os import ast
import getopt
import glob
import importlib.machinery import importlib.machinery
import importlib.util import importlib.util
import os
import sys import sys
import glob
import time import time
import getopt
import ast
import tokenize import tokenize
from collections import defaultdict from collections import defaultdict
from dataclasses import dataclass, field from dataclasses import dataclass, field
@ -173,7 +153,7 @@ __version__ = '1.5'
# The normal pot-file header. msgmerge and Emacs's po-mode work better if it's # The normal pot-file header. msgmerge and Emacs's po-mode work better if it's
# there. # there.
pot_header = _('''\ pot_header = '''\
# SOME DESCRIPTIVE TITLE. # SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR ORGANIZATION # Copyright (C) YEAR ORGANIZATION
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
@ -190,7 +170,7 @@ msgstr ""
"Content-Transfer-Encoding: %(encoding)s\\n" "Content-Transfer-Encoding: %(encoding)s\\n"
"Generated-By: pygettext.py %(version)s\\n" "Generated-By: pygettext.py %(version)s\\n"
''') '''
def usage(code, msg=''): def usage(code, msg=''):
@ -204,7 +184,7 @@ def make_escapes(pass_nonascii):
global escapes, escape global escapes, escape
if pass_nonascii: if pass_nonascii:
# Allow non-ascii characters to pass through so that e.g. 'msgid # Allow non-ascii characters to pass through so that e.g. 'msgid
# "Höhe"' would result not result in 'msgid "H\366he"'. Otherwise we # "Höhe"' would result not result in 'msgid "H\366he"'. Otherwise we
# escape any character outside the 32..126 range. # escape any character outside the 32..126 range.
mod = 128 mod = 128
escape = escape_ascii escape = escape_ascii
@ -224,6 +204,7 @@ def make_escapes(pass_nonascii):
def escape_ascii(s, encoding): def escape_ascii(s, encoding):
return ''.join(escapes[ord(c)] if ord(c) < 128 else c for c in s) return ''.join(escapes[ord(c)] if ord(c) < 128 else c for c in s)
def escape_nonascii(s, encoding): def escape_nonascii(s, encoding):
return ''.join(escapes[b] for b in s.encode(encoding)) return ''.join(escapes[b] for b in s.encode(encoding))
@ -416,7 +397,7 @@ class TokenEater:
if func_name not in opts.keywords: if func_name not in opts.keywords:
continue continue
if len(call.args) != 1: if len(call.args) != 1:
print(_( print((
'*** %(file)s:%(lineno)s: Seen unexpected amount of' '*** %(file)s:%(lineno)s: Seen unexpected amount of'
' positional arguments in gettext call: %(source_segment)s' ' positional arguments in gettext call: %(source_segment)s'
) % { ) % {
@ -426,7 +407,7 @@ class TokenEater:
}, file=sys.stderr) }, file=sys.stderr)
continue continue
if call.keywords: if call.keywords:
print(_( print((
'*** %(file)s:%(lineno)s: Seen unexpected keyword arguments' '*** %(file)s:%(lineno)s: Seen unexpected keyword arguments'
' in gettext call: %(source_segment)s' ' in gettext call: %(source_segment)s'
) % { ) % {
@ -437,7 +418,7 @@ class TokenEater:
continue continue
arg = call.args[0] arg = call.args[0]
if not isinstance(arg, ast.Constant): if not isinstance(arg, ast.Constant):
print(_( print((
'*** %(file)s:%(lineno)s: Seen unexpected argument type' '*** %(file)s:%(lineno)s: Seen unexpected argument type'
' in gettext call: %(source_segment)s' ' in gettext call: %(source_segment)s'
) % { ) % {
@ -550,7 +531,7 @@ class TokenEater:
) )
def warn_unexpected_token(self, token): def warn_unexpected_token(self, token):
print(_( print((
'*** %(file)s:%(lineno)s: Seen unexpected token "%(token)s"' '*** %(file)s:%(lineno)s: Seen unexpected token "%(token)s"'
) % { ) % {
'token': token, 'token': token,
@ -677,7 +658,7 @@ def main():
elif opt in ('-S', '--style'): elif opt in ('-S', '--style'):
options.locationstyle = locations.get(arg.lower()) options.locationstyle = locations.get(arg.lower())
if options.locationstyle is None: if options.locationstyle is None:
usage(1, _('Invalid value for --style: %s') % arg) usage(1, f'Invalid value for --style: {arg}')
elif opt in ('-o', '--output'): elif opt in ('-o', '--output'):
options.outfile = arg options.outfile = arg
elif opt in ('-p', '--output-dir'): elif opt in ('-p', '--output-dir'):
@ -685,13 +666,13 @@ def main():
elif opt in ('-v', '--verbose'): elif opt in ('-v', '--verbose'):
options.verbose = 1 options.verbose = 1
elif opt in ('-V', '--version'): elif opt in ('-V', '--version'):
print(_('pygettext.py (xgettext for Python) %s') % __version__) print(f'pygettext.py (xgettext for Python) {__version__}')
sys.exit(0) sys.exit(0)
elif opt in ('-w', '--width'): elif opt in ('-w', '--width'):
try: try:
options.width = int(arg) options.width = int(arg)
except ValueError: except ValueError:
usage(1, _('--width argument must be an integer: %s') % arg) usage(1, f'--width argument must be an integer: {arg}')
elif opt in ('-x', '--exclude-file'): elif opt in ('-x', '--exclude-file'):
options.excludefilename = arg options.excludefilename = arg
elif opt in ('-X', '--no-docstrings'): elif opt in ('-X', '--no-docstrings'):
@ -719,8 +700,8 @@ def main():
with open(options.excludefilename) as fp: with open(options.excludefilename) as fp:
options.toexclude = fp.readlines() options.toexclude = fp.readlines()
except IOError: except IOError:
print(_( print(f"Can't read --exclude-file: {options.excludefilename}",
"Can't read --exclude-file: %s") % options.excludefilename, file=sys.stderr) file=sys.stderr)
sys.exit(1) sys.exit(1)
else: else:
options.toexclude = [] options.toexclude = []
@ -739,12 +720,12 @@ def main():
for filename in args: for filename in args:
if filename == '-': if filename == '-':
if options.verbose: if options.verbose:
print(_('Reading standard input')) print('Reading standard input')
fp = sys.stdin.buffer fp = sys.stdin.buffer
closep = 0 closep = 0
else: else:
if options.verbose: if options.verbose:
print(_('Working on %s') % filename) print(f'Working on {filename}')
fp = open(filename, 'rb') fp = open(filename, 'rb')
closep = 1 closep = 1
try: try:
@ -779,7 +760,3 @@ def main():
if __name__ == '__main__': if __name__ == '__main__':
main() main()
# some more test strings
# this one creates a warning
_('*** Seen unexpected token "%(token)s"') % {'token': 'test'}
_('more' 'than' 'one' 'string')