Commit bd69dff
fix(rewrite): guard a chained comparison's explanation too
Short-circuiting the chain nested the statements that evaluate a link
past the first, but not the statements that explain it, so the failure
branch ran a skipped link's explanation against temporaries the link
never assigned:
assert 1 < 0 < (a or b)
raised ``AttributeError: 'NoneType' object has no attribute 'append'``
instead of failing. visit_BoolOp builds its explanation by creating a
list in the main body and appending to it from expl_stmts; nesting only
the body left the list None while the appends ran unconditionally.
SirHegel found this against the branch and named the fix -- nest
expl_stmts on the same condition, the way visit_BoolOp nests both -- in
pytest-dev#14822 (comment),
having reduced it from his own pytest-dev#14918. What follows is his idea; two
details are worth recording.
Most links explain themselves in the format context alone and contribute
no statements, and an ``if`` with an empty body is not valid syntax, so
the guards are attached innermost first and the empty ones dropped --
attaching a child fills its parent, so a parent is only known to be empty
once its child has been placed.
The names to pre-bind now include the @py_format ones created inside
those guarded blocks, which the outer format context reads. Collecting
them by walking the blocks is what makes them reachable at all, but the
walk must not take everything it finds: a walrus target inside a skipped
link belongs to the user, and Python leaves it unbound. Binding it to
None to keep the explanation readable would be visible after the
assertion, so _rewriter_temporaries() takes only names the rewriter
itself makes.
That last point is a second failure mode, which the report did not
cover: the explanation of a walrus reads its target to decide how to show
it, and a skipped link never bound it.
assert 1 < 0 < (w := 1) # UnboundLocalError: 'w'
assert 1 < 0 < identity(w := 1) # likewise
Nesting does not reach it -- the read sits in the compare's own format
dict, which is built eagerly and belongs to no link -- and ``'w' in
locals()`` does not guard it, because the fallback hands the value to
_should_repr_global_name(). visit_NamedExpr now asks whether the target
is a global before reading it, and shows the bare name when it is
neither. An undefined name inside a skipped operand failed the same way
with NameError, and is fixed by the nesting.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>1 parent 86a550b commit bd69dff
2 files changed
Lines changed: 137 additions & 11 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
545 | 545 | | |
546 | 546 | | |
547 | 547 | | |
| 548 | + | |
| 549 | + | |
| 550 | + | |
| 551 | + | |
| 552 | + | |
| 553 | + | |
| 554 | + | |
| 555 | + | |
| 556 | + | |
| 557 | + | |
| 558 | + | |
| 559 | + | |
| 560 | + | |
| 561 | + | |
| 562 | + | |
| 563 | + | |
| 564 | + | |
| 565 | + | |
| 566 | + | |
548 | 567 | | |
549 | 568 | | |
550 | 569 | | |
| |||
951 | 970 | | |
952 | 971 | | |
953 | 972 | | |
954 | | - | |
| 973 | + | |
| 974 | + | |
| 975 | + | |
| 976 | + | |
| 977 | + | |
| 978 | + | |
| 979 | + | |
| 980 | + | |
| 981 | + | |
| 982 | + | |
| 983 | + | |
| 984 | + | |
| 985 | + | |
| 986 | + | |
955 | 987 | | |
956 | 988 | | |
957 | 989 | | |
| |||
1183 | 1215 | | |
1184 | 1216 | | |
1185 | 1217 | | |
1186 | | - | |
1187 | | - | |
1188 | | - | |
1189 | | - | |
1190 | | - | |
| 1218 | + | |
| 1219 | + | |
| 1220 | + | |
| 1221 | + | |
| 1222 | + | |
| 1223 | + | |
| 1224 | + | |
1191 | 1225 | | |
1192 | | - | |
| 1226 | + | |
| 1227 | + | |
| 1228 | + | |
| 1229 | + | |
1193 | 1230 | | |
1194 | 1231 | | |
1195 | 1232 | | |
1196 | | - | |
| 1233 | + | |
1197 | 1234 | | |
1198 | | - | |
| 1235 | + | |
| 1236 | + | |
| 1237 | + | |
1199 | 1238 | | |
| 1239 | + | |
| 1240 | + | |
| 1241 | + | |
| 1242 | + | |
| 1243 | + | |
1200 | 1244 | | |
1201 | 1245 | | |
1202 | 1246 | | |
| |||
1213 | 1257 | | |
1214 | 1258 | | |
1215 | 1259 | | |
| 1260 | + | |
| 1261 | + | |
| 1262 | + | |
| 1263 | + | |
| 1264 | + | |
| 1265 | + | |
| 1266 | + | |
| 1267 | + | |
| 1268 | + | |
1216 | 1269 | | |
1217 | | - | |
1218 | | - | |
| 1270 | + | |
| 1271 | + | |
| 1272 | + | |
| 1273 | + | |
| 1274 | + | |
| 1275 | + | |
| 1276 | + | |
| 1277 | + | |
1219 | 1278 | | |
1220 | 1279 | | |
1221 | 1280 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1277 | 1277 | | |
1278 | 1278 | | |
1279 | 1279 | | |
| 1280 | + | |
| 1281 | + | |
| 1282 | + | |
| 1283 | + | |
| 1284 | + | |
| 1285 | + | |
| 1286 | + | |
| 1287 | + | |
| 1288 | + | |
| 1289 | + | |
| 1290 | + | |
| 1291 | + | |
| 1292 | + | |
| 1293 | + | |
| 1294 | + | |
| 1295 | + | |
| 1296 | + | |
| 1297 | + | |
| 1298 | + | |
| 1299 | + | |
| 1300 | + | |
| 1301 | + | |
| 1302 | + | |
| 1303 | + | |
| 1304 | + | |
| 1305 | + | |
| 1306 | + | |
| 1307 | + | |
| 1308 | + | |
| 1309 | + | |
| 1310 | + | |
| 1311 | + | |
| 1312 | + | |
| 1313 | + | |
| 1314 | + | |
| 1315 | + | |
| 1316 | + | |
| 1317 | + | |
| 1318 | + | |
| 1319 | + | |
| 1320 | + | |
| 1321 | + | |
| 1322 | + | |
| 1323 | + | |
| 1324 | + | |
| 1325 | + | |
| 1326 | + | |
| 1327 | + | |
| 1328 | + | |
| 1329 | + | |
| 1330 | + | |
| 1331 | + | |
| 1332 | + | |
| 1333 | + | |
| 1334 | + | |
| 1335 | + | |
| 1336 | + | |
| 1337 | + | |
| 1338 | + | |
| 1339 | + | |
| 1340 | + | |
| 1341 | + | |
| 1342 | + | |
| 1343 | + | |
| 1344 | + | |
| 1345 | + | |
| 1346 | + | |
1280 | 1347 | | |
1281 | 1348 | | |
1282 | 1349 | | |
| |||
0 commit comments