diff options
author | jack1142 <6032823+jack1142@users.noreply.github.com> | 2020-11-09 22:50:45 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-11-09 22:50:45 (GMT) |
commit | bfc6b63102d37ccb58a71711e2342143cd9f4d86 (patch) | |
tree | 7363462e163ebfa86f099802493389b42f217871 /Tools/i18n | |
parent | 1f73c320e2921605c4963e202f6bdac1ef18f2ce (diff) | |
download | cpython-bfc6b63102d37ccb58a71711e2342143cd9f4d86.zip cpython-bfc6b63102d37ccb58a71711e2342143cd9f4d86.tar.gz cpython-bfc6b63102d37ccb58a71711e2342143cd9f4d86.tar.bz2 |
bpo-36310: Allow pygettext.py to detect calls to gettext in f-strings. (GH-19875)
Adds support to Tools/i18n/pygettext.py for gettext calls in f-strings. This process is done by parsing the f-strings, processing each value, and flagging the ones which contain a gettext call.
Co-authored-by: Batuhan Taskaya <batuhanosmantaskaya@gmail.com>
Diffstat (limited to 'Tools/i18n')
-rwxr-xr-x | Tools/i18n/pygettext.py | 53 |
1 files changed, 53 insertions, 0 deletions
diff --git a/Tools/i18n/pygettext.py b/Tools/i18n/pygettext.py index b1d281d..9dd65c2 100755 --- a/Tools/i18n/pygettext.py +++ b/Tools/i18n/pygettext.py @@ -162,6 +162,7 @@ import sys import glob import time import getopt +import ast import token import tokenize @@ -343,6 +344,58 @@ class TokenEater: return if ttype == tokenize.NAME and tstring in opts.keywords: self.__state = self.__keywordseen + return + if ttype == tokenize.STRING: + maybe_fstring = ast.parse(tstring, mode='eval').body + if not isinstance(maybe_fstring, ast.JoinedStr): + return + for value in filter(lambda node: isinstance(node, ast.FormattedValue), + maybe_fstring.values): + for call in filter(lambda node: isinstance(node, ast.Call), + ast.walk(value)): + func = call.func + if isinstance(func, ast.Name): + func_name = func.id + elif isinstance(func, ast.Attribute): + func_name = func.attr + else: + continue + + if func_name not in opts.keywords: + continue + if len(call.args) != 1: + print(_( + '*** %(file)s:%(lineno)s: Seen unexpected amount of' + ' positional arguments in gettext call: %(source_segment)s' + ) % { + 'source_segment': ast.get_source_segment(tstring, call) or tstring, + 'file': self.__curfile, + 'lineno': lineno + }, file=sys.stderr) + continue + if call.keywords: + print(_( + '*** %(file)s:%(lineno)s: Seen unexpected keyword arguments' + ' in gettext call: %(source_segment)s' + ) % { + 'source_segment': ast.get_source_segment(tstring, call) or tstring, + 'file': self.__curfile, + 'lineno': lineno + }, file=sys.stderr) + continue + arg = call.args[0] + if not isinstance(arg, ast.Constant): + print(_( + '*** %(file)s:%(lineno)s: Seen unexpected argument type' + ' in gettext call: %(source_segment)s' + ) % { + 'source_segment': ast.get_source_segment(tstring, call) or tstring, + 'file': self.__curfile, + 'lineno': lineno + }, file=sys.stderr) + continue + if isinstance(arg.value, str): + self.__addentry(arg.value, lineno) def __suiteseen(self, ttype, tstring, lineno): # skip over any enclosure pairs until we see the colon |