CPython folds constants in two different places. fold_binop in Python/ast_preprocess.c:370-383@v3.15.0rc1#fold_binop rewrites the AST before code generation, and eval_const_binop in Python/flowgraph.c:1860-1866@v3.15.0rc1#eval_const_binop folds again on the control flow graph after it.
pyxray.compiler.stages cannot show the first one. It calls ast.parse and hands the result straight to _testinternalcapi.compiler_codegen, and ast.parse does not run the preprocessor, so the tree the code generator sees in a lesson has not been through _PyAST_Preprocess. The consequence is that 6 * 7 reaches code generation as LOAD_CONST 6, LOAD_CONST 7, BINARY_OP 5 and is folded by the CFG optimizer, whereas inside a real compile() the AST folder gets there first and the code generator never emits the multiply at all.
T01 handles this by saying so in the prose rather than by letting the reader conclude the AST folder does not exist. That is the right answer for one lesson and the wrong answer to leave in the tool, because T05 is about exactly this stage and will want to show both folders side by side.
What is needed is a way to run the preprocessor from Python. _PyAST_Preprocess is not exported, so the options are to check whether _testinternalcapi exposes something equivalent, to add a hook upstream, or to give up and have stages() carry both trees where the second one is reconstructed by comparing the real compile() output against the raw one. The last is a fake and should be the fallback, not the plan.
Worth doing before T05. Not worth blocking T02 through T04 on.
CPython folds constants in two different places.
fold_binopinPython/ast_preprocess.c:370-383@v3.15.0rc1#fold_binoprewrites the AST before code generation, andeval_const_binopinPython/flowgraph.c:1860-1866@v3.15.0rc1#eval_const_binopfolds again on the control flow graph after it.pyxray.compiler.stagescannot show the first one. It callsast.parseand hands the result straight to_testinternalcapi.compiler_codegen, andast.parsedoes not run the preprocessor, so the tree the code generator sees in a lesson has not been through_PyAST_Preprocess. The consequence is that6 * 7reaches code generation asLOAD_CONST 6, LOAD_CONST 7, BINARY_OP 5and is folded by the CFG optimizer, whereas inside a realcompile()the AST folder gets there first and the code generator never emits the multiply at all.T01 handles this by saying so in the prose rather than by letting the reader conclude the AST folder does not exist. That is the right answer for one lesson and the wrong answer to leave in the tool, because T05 is about exactly this stage and will want to show both folders side by side.
What is needed is a way to run the preprocessor from Python.
_PyAST_Preprocessis not exported, so the options are to check whether_testinternalcapiexposes something equivalent, to add a hook upstream, or to give up and havestages()carry both trees where the second one is reconstructed by comparing the realcompile()output against the raw one. The last is a fake and should be the fallback, not the plan.Worth doing before T05. Not worth blocking T02 through T04 on.