[
https://issues.apache.org/jira/browse/THRIFT-6114?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Jens Geyer resolved THRIFT-6114.
--------------------------------
Fix Version/s: 0.25.0
Resolution: Fixed
> Python service/function names that are Python keywords generate unimportable
> modules and a broken -remote script
> ----------------------------------------------------------------------------------------------------------------
>
> Key: THRIFT-6114
> URL: https://issues.apache.org/jira/browse/THRIFT-6114
> Project: Thrift
> Issue Type: Bug
> Components: Python - Compiler
> Reporter: Jens Geyer
> Priority: Major
> Fix For: 0.25.0
>
> Time Spent: 20m
> Remaining Estimate: 0h
>
> Follow-up to THRIFT-5927 (Python keyword-escaping) and THRIFT-6113
> (regression test wasn't actually running in CI).
> THRIFT-5927 switched Python codegen from hard-rejecting reserved-keyword
> identifiers at compile time (validate_id() against the full keyword set) to
> escaping them with a trailing underscore. That escaping was wired into
> struct/enum/field/exception generation and the service Client/Processor class
> bodies, but was missed in two places that are exercised by the existing
> Thrift5927.thrift test fixture (service continue { import return(1: False
> while) throws (1: True yield) }):
> 1. t_py_generator::generate_service() builds the service's own module
> filename from the raw, unescaped service name (t_py_generator.cc:1293:
> "package_dir_ + "/" + service_name_ + ".py""). For a service named "continue"
> this produces continue.py. That file compiles fine in isolation, but it can
> only be reached with importlib -- neither statement form a normal consumer
> (or Thrift's own generated -remote script) would use actually parses:
> >>> import ast
> >>> ast.parse('import thrift5927.continue')
> SyntaxError: invalid syntax
> >>> ast.parse('from thrift5927 import continue')
> SyntaxError: invalid syntax
> 2. t_py_generator::generate_service_remote() (t_py_generator.cc:1765-1949),
> which emits the "<service>-remote" CLI helper script, never calls
> maybe_escape_identifier() at all. For Thrift5927.thrift this produces a
> script with three genuine syntax errors, reproduced with py_compile:
> from thrift5927 import continue # line 19 -- import target is a
> keyword
> client = continue.Client(protocol) # line 104 -- keyword used as an
> identifier
> client.return(eval(args[0]),)) # line 111 -- keyword used as a
> method name
> py_compile.compile() on this file raises "SyntaxError: invalid syntax" at
> line 19.
> Net effect: for a keyword-named service or function, THRIFT-5927 replaced a
> safe, loud compile-time rejection with a silent generation of broken Python.
> This is a regression introduced by THRIFT-5927, not a pre-existing issue --
> prior to that fix, compiling Thrift5927.thrift's service/function names would
> have failed validate_id() outright.
> The existing test (lib/py/test/test_compiler/test_keyword_escape.py) does not
> catch this because it only globs **/*.py for compileability; the -remote
> script is intentionally generated without a .py extension (matching every
> other language's convention for the executable helper script) and is
> invisible to that glob.
> Proposed fix (scoped to what's covered by the existing fixture):
> - Escape service_name_ at its three real identifier-position usages: the
> module filename (t_py_generator.cc:1293), the "from <module> import
> <service>" line in generate_service_remote (:1793), and the "client =
> <service>.Client(...)" line (:1896). The CLI script's own filename
> (<service>-remote, :1776) is left as-is since it is a shell-invoked filename,
> not a Python identifier -- keeping the literal IDL name there is more useful
> for users typing it at a shell.
> - Escape the function name used for the client dispatch call in
> generate_service_remote (:1920, "client.<function>(...)"), matching the
> already-escaped method name on the generated Client class. The other
> get_name() uses in that function are inside string literals (help text, the
> sys.argv command-word comparison) and correctly stay unescaped since they
> reflect the original IDL name a CLI user would type.
> - Extend test_keyword_escape.py to also compile-check generated "*-remote"
> files, not just "*.py".
> Out of scope for this ticket (found while investigating, but not covered by
> the current fixture and needs its own fixture + a broader look at the shared
> type_name()/type_to_spec_args() helpers): t_service extends (inheritance)
> references and cross-module (included-file) type references also build Python
> import/attribute-access strings from unescaped names
> (t_py_generator.cc:1298-1301, 1387-1388, 1432-1433, 1978-1979, and the
> type_name()/type_to_spec_args() helpers generally). Flagging for a separate
> follow-up rather than bundling an unverified, untested code path into this
> fix.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)